Pulumi 基础设施即代码
使用 Pulumi 和 TypeScript、Python、Go 的现代基础设施即代码示例
💻 Pulumi TypeScript AWS typescript
🟢 simple
⭐⭐
使用 Pulumi 和 TypeScript 部署 AWS 基础设施
⏱️ 15 min
🏷️ pulumi, typescript, aws, serverless, iac
Prerequisites:
Node.js, AWS account, Pulumi CLI
// Pulumi TypeScript for AWS
import * as pulumi from '@pulumi/pulumi';
import * as aws from '@pulumi/aws';
// Get AWS provider configuration
const config = new pulumi.Config();
const stackName = pulumi.getStack();
const environment = stackName === 'prod' ? 'production' : 'development';
// Create an AWS resource (S3 Bucket)
const bucket = new aws.s3.Bucket('my-app-bucket', {
bucket: pulumi.interpolate`my-app-bucket-${stackName}-${Math.floor(Math.random() * 1000000)}`,
acl: 'private',
versioning: {
enabled: true,
},
tags: {
Name: pulumi.interpolate`my-app-bucket-${stackName}`,
Environment: environment,
Project: 'pulumi-demo',
ManagedBy: 'pulumi'
},
website: {
indexDocument: 'index.html',
errorDocument: 'error.html'
},
forceDestroy: true
});
// Create IAM role for Lambda
const lambdaRole = new aws.iam.Role('app-lambda-role', {
assumeRolePolicy: JSON.stringify({
Version: '2012-10-17',
Statement: [{
Action: 'sts:AssumeRole',
Effect: 'Allow',
Principal: {
Service: 'lambda.amazonaws.com'
}
}]
}),
tags: {
Name: pulumi.interpolate`app-lambda-role-${stackName}`,
Environment: environment
}
});
// Attach basic execution policy
new aws.iam.RolePolicyAttachment('app-lambda-basic-execution', {
role: lambdaRole.name,
policyArn: aws.iam.ManagedPolicies.AWSLambdaBasicExecutionRole,
});
// Create Lambda function
const lambdaFunction = new aws.lambda.Function('app-api-function', {
name: pulumi.interpolate`app-api-${stackName}`,
runtime: 'nodejs18.x',
handler: 'index.handler',
role: lambdaRole.arn,
s3Bucket: bucket.id,
s3Key: 'api/function.zip',
timeout: 30,
memorySize: 256,
environment: {
variables: {
NODE_ENV: environment,
BUCKET_NAME: bucket.id
}
},
tags: {
Name: pulumi.interpolate`app-api-${stackName}`,
Environment: environment
}
});
// Create API Gateway
const api = new aws.apigateway.RestApi('app-api', {
name: pulumi.interpolate`app-api-${stackName}`,
description: pulumi.interpolate`API Gateway for Pulumi demo in ${environment}`,
endpointConfiguration: {
types: 'REGIONAL',
}
});
// Create API resource
const apiResource = new aws.apigateway.Resource('app-api-resource', {
restApi: api.id,
parentId: api.rootResourceId,
pathPart: '{proxy+}'
});
// Create API method
const apiMethod = new aws.apigateway.Method('app-api-method', {
restApi: api.id,
resourceId: apiResource.id,
httpMethod: 'ANY',
authorization: 'NONE'
});
// Create API integration
const apiIntegration = new aws.apigateway.Integration('app-api-integration', {
restApi: api.id,
resourceId: apiResource.id,
httpMethod: apiMethod.httpMethod,
integrationHttpMethod: 'POST',
type: 'AWS_PROXY',
uri: lambdaFunction.invokeArn
});
// Grant API Gateway permission to invoke Lambda
const lambdaPermission = new aws.lambda.Permission('app-api-lambda-permission', {
statementId: 'AllowAPIGatewayInvoke',
action: 'lambda:InvokeFunction',
function: lambdaFunction.name,
principal: 'apigateway.amazonaws.com',
sourceArn: pulumi.interpolate`arn:aws:execute-api:${aws.getRegion()}:${aws.getAccountId()}:${api.id}/*/*`
});
// Create CloudWatch Log Group for Lambda
const logGroup = new aws.cloudwatch.LogGroup('app-lambda-logs', {
name: pulumi.interpolate`/aws/lambda/${lambdaFunction.name}`,
retentionInDays: 14,
tags: {
Name: pulumi.interpolate`${lambdaFunction.name}-logs`,
Environment: environment
}
});
// Output values
export const bucketName = bucket.id;
export const bucketArn = bucket.arn;
export const apiEndpoint = pulumi.interpolate`https://${api.id}.execute-api.${aws.getRegion()}.amazonaws.com/prod`;
export const lambdaFunctionName = lambdaFunction.name;
export const logGroupName = logGroup.name;
// Create stack outputs
new pulumi.Output('bucket_name', bucketName);
new pulumi.Output('api_endpoint', apiEndpoint);
new pulumi.Output('lambda_function_name', lambdaFunctionName);
// Stack exports for cross-stack references
if (environment === 'production') {
bucket.id.apply(id => pulumi.stackReference('prod', id));
api.id.apply(id => pulumi.stackReference('prod-api', id));
}
💻 Pulumi Python Google Cloud python
🟡 intermediate
⭐⭐⭐
使用 Pulumi 和 Python 部署 GCP 基础设施
⏱️ 25 min
🏷️ pulumi, python, gcp, cloud run, cloud sql
Prerequisites:
Python, GCP project, Pulumi CLI
# Pulumi Python for Google Cloud Platform
import pulumi
import pulumi_gcp as gcp
# Get configuration
config = pulumi.Config()
stack_name = pulumi.get_stack()
environment = 'production' if stack_name == 'prod' else 'development'
project_id = config.require('project_id')
region = config.get('region', 'us-central1')
# Create GCP provider
gcp_provider = gcp.provider.Provider('gcp',
project=project_id,
region=region
)
# Create VPC network
vpc_network = gcp.compute.Network('app-vpc',
name=f'app-vpc-{stack_name}',
auto_create_subnetworks=False,
description=f'VPC for application in {environment}',
routing_mode='REGIONAL',
opts=pulumi.ResourceOptions(provider=gcp_provider)
)
# Create subnets
public_subnet = gcp.compute.Subnetwork('app-public-subnet',
name=f'app-public-subnet-{stack_name}',
ip_cidr_range='10.0.1.0/24',
region=region,
network=vpc_network.id,
private_ip_google_access=False,
opts=pulumi.ResourceOptions(provider=gcp_provider)
)
private_subnet = gcp.compute.Subnetwork('app-private-subnet',
name=f'app-private-subnet-{stack_name}',
ip_cidr_range='10.0.2.0/24',
region=region,
network=vpc_network.id,
private_ip_google_access=True,
opts=pulumi.ResourceOptions(provider=gcp_provider)
)
# Create Cloud Storage bucket
bucket_suffix = pulumi.random.RandomString('bucket-suffix',
length=8,
special=False,
upper=False
).result
storage_bucket = gcp.storage.Bucket('app-storage-bucket',
name=bucket_suffix.apply(lambda suffix: f'app-storage-bucket-{stack_name}-{suffix}'),
location=region,
storage_class='STANDARD',
uniform_bucket_level_access=True,
versioning= {
'enabled': True
},
labels={
'environment': environment,
'managed-by': 'pulumi'
},
opts=pulumi.ResourceOptions(provider=gcp_provider)
)
# Create Cloud SQL instance
sql_instance = gcp.sql.DatabaseInstance('app-sql-instance',
name=f'app-sql-instance-{stack_name}',
database_version='POSTGRES_14',
region=region,
settings={
'tier': 'db-g1-small',
'disk_size': 20,
'disk_type': 'PD_SSD',
'ip_configuration': {
'ipv4_enabled': False,
'private_network': vpc_network.id,
'authorized_networks': []
},
'backup_configuration': {
'enabled': True,
'binary_log_enabled': True
}
},
deletion_protection=False,
opts=pulumi.ResourceOptions(provider=gcp_provider)
)
# Create SQL database
sql_database = gcp.sql.Database('app-sql-database',
name='app_database',
instance=sql_instance.name,
opts=pulumi.ResourceOptions(provider=gcp_provider)
)
# Create Cloud Run service
cloud_run_service = gcp.cloudrun.Service('app-cloudrun-service',
name=f'app-service-{stack_name}',
location=region,
template={
'spec': {
'containers': [{
'image': 'gcr.io/cloudrun/hello:latest',
'ports': [{
'name': 'http1',
'containerPort': 8080
}],
'envs': [
{
'name': 'DATABASE_HOST',
'value': sql_instance.private_ip_address.apply(lambda ip: f'{ip}:5432')
},
{
'name': 'DATABASE_NAME',
'value': sql_database.name
},
{
'name': 'STORAGE_BUCKET',
'value': storage_bucket.name
},
{
'name': 'ENVIRONMENT',
'value': environment
}
]
}],
'container_concurrency': 80,
'timeout_seconds': 30
}
},
traffic=[{
'percent': 100,
'latest_revision': True
}],
opts=pulumi.ResourceOptions(provider=gcp_provider)
)
# Create IAM policy for Cloud Run
cloud_run_iam = gcp.cloudrun.IamPolicy('app-cloudrun-iam',
location=region,
project=project_id,
bindings=[{
'role': 'roles/run.invoker',
'members': ['allUsers']
}],
cloudrun=cloud_run_service.name,
opts=pulumi.ResourceOptions(provider=gcp_provider)
)
# Create Cloud Scheduler job
scheduler_job = gcp.cloudscheduler.Job('app-scheduler-job',
name=f'app-scheduler-{stack_name}',
description='Scheduled job for data processing',
schedule='0 2 * * *', # Daily at 2 AM
time_zone='America/Los_Angeles',
pubsub_target={
'topic_name': gcp.pubsub.Topic('app-topic',
name=f'app-topic-{stack_name}',
opts=pulumi.ResourceOptions(provider=gcp_provider)
).id.apply(lambda id: f'projects/{project_id}/topics/{id}'),
'data': '{"task": "daily_cleanup"}'
},
opts=pulumi.ResourceOptions(provider=gcp_provider)
)
# Create Cloud Function for background processing
cloud_function = gcp.cloudfunctions.Function('app-background-function',
name=f'app-background-func-{stack_name}',
description='Background processing function',
runtime='python39',
available_memory_mb=256,
source_archive_bucket=storage_bucket.name,
source_archive_object=gcp.storage.BucketObject('function-source',
name='background-function.zip',
bucket=storage_bucket.name,
source=pulumi.FileArchive('./function-source'),
opts=pulumi.ResourceOptions(provider=gcp_provider)
).name,
entry_point='handler',
event_trigger={
'event_type': 'google.pubsub.topic.publish',
'resource': scheduler_job.pubsub_target.topic_name
},
opts=pulumi.ResourceOptions(provider=gcp_provider)
)
# Export values
pulumi.export('project_id', project_id)
pulumi.export('vpc_network_name', vpc_network.name)
pulumi.export('public_subnet_name', public_subnet.name)
pulumi.export('private_subnet_name', private_subnet.name)
pulumi.export('storage_bucket_name', storage_bucket.name)
pulumi.export('sql_instance_name', sql_instance.name)
pulumi.export('sql_database_name', sql_database.name)
pulumi.export('sql_instance_ip', sql_instance.private_ip_address)
pulumi.export('cloud_run_service_url', cloud_run_service.statuses[0].url)
pulumi.export('scheduler_job_name', scheduler_job.name)
pulumi.export('cloud_function_name', cloud_function.name)
💻 Pulumi Go Kubernetes go
🟡 intermediate
⭐⭐⭐⭐
使用 Pulumi 和 Go 部署 Kubernetes 资源
⏱️ 30 min
🏷️ pulumi, go, kubernetes, helm, deployment
Prerequisites:
Go programming, Kubernetes, Helm
// Pulumi Go for Kubernetes
package main
import (
"context"
"fmt"
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes"
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/apps/v1"
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/core/v1"
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/networking/v1"
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/rbac/v1"
"github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/helm/v3"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
// Get configuration
config := ctx.NewConfig()
stackName := ctx.Stack()
environment := "development"
if stackName == "prod" {
environment = "production"
}
namespaceName := fmt.Sprintf("app-%s", stackName)
// Create Kubernetes provider
k8sProvider, err := kubernetes.NewProvider(ctx, "k8s", &kubernetes.ProviderArgs{
Kubeconfig: config.Get("kubeconfig"),
})
if err != nil {
return err
}
// Create namespace
namespace, err := v1.NewNamespace(ctx, "app-namespace", &v1.NamespaceArgs{
Metadata: &v1.ObjectMetaArgs{
Name: pulumi.String(namespaceName),
Labels: pulumi.StringMap{
"name": pulumi.String(namespaceName),
"environment": pulumi.String(environment),
"managed-by": pulumi.String("pulumi"),
},
},
}, pulumi.Provider(k8sProvider))
if err != nil {
return err
}
// Create ConfigMap for application configuration
appConfigMap, err := v1.NewConfigMap(ctx, "app-config", &v1.ConfigMapArgs{
Metadata: &v1.ObjectMetaArgs{
Name: pulumi.String("app-config"),
Namespace: namespace.Name,
},
Data: pulumi.StringMap{
"API_URL": pulumi.String("https://api.example.com"),
"LOG_LEVEL": pulumi.String("info"),
"REDIS_HOST": pulumi.String("redis-service"),
"REDIS_PORT": pulumi.String("6379"),
"DB_HOST": pulumi.String("postgres-service"),
"DB_PORT": pulumi.String("5432"),
"ENVIRONMENT": pulumi.String(environment),
},
}, pulumi.Provider(k8sProvider))
if err != nil {
return err
}
// Create Secret for sensitive data
appSecret, err := v1.NewSecret(ctx, "app-secret", &v1.SecretArgs{
Metadata: &v1.ObjectMetaArgs{
Name: pulumi.String("app-secret"),
Namespace: namespace.Name,
},
StringData: pulumi.StringMap{
"DB_PASSWORD": pulumi.String("changeme123!"),
"API_KEY": pulumi.String("secret-api-key"),
"JWT_SECRET": pulumi.String("jwt-secret-key"),
},
}, pulumi.Provider(k8sProvider))
if err != nil {
return err
}
// Create Redis deployment
redisDeployment, err := v1.NewDeployment(ctx, "redis-deployment", &v1.DeploymentArgs{
Metadata: &v1.ObjectMetaArgs{
Name: pulumi.String("redis"),
Namespace: namespace.Name,
Labels: pulumi.StringMap{
"app": pulumi.String("redis"),
"tier": pulumi.String("cache"),
},
},
Spec: &v1.DeploymentSpecArgs{
Replicas: pulumi.Int(1),
Selector: &v1.LabelSelectorArgs{
MatchLabels: pulumi.StringMap{
"app": pulumi.String("redis"),
},
},
Template: &v1.PodTemplateSpecArgs{
Metadata: &v1.ObjectMetaArgs{
Labels: pulumi.StringMap{
"app": pulumi.String("redis"),
},
},
Spec: &v1.PodSpecArgs{
Containers: v1.ContainerArray{
&v1.ContainerArgs{
Name: pulumi.String("redis"),
Image: pulumi.String("redis:7-alpine"),
Ports: v1.ContainerPortArray{
&v1.ContainerPortArgs{
ContainerPort: pulumi.Int(6379),
},
},
Resources: &v1.ResourceRequirementsArgs{
Requests: pulumi.StringMap{
"memory": pulumi.String("64Mi"),
"cpu": pulumi.String("250m"),
},
Limits: pulumi.StringMap{
"memory": pulumi.String("128Mi"),
"cpu": pulumi.String("500m"),
},
},
},
},
},
},
},
}, pulumi.Provider(k8sProvider))
if err != nil {
return err
}
// Create Redis service
redisService, err := v1.NewService(ctx, "redis-service", &v1.ServiceArgs{
Metadata: &v1.ObjectMetaArgs{
Name: pulumi.String("redis-service"),
Namespace: namespace.Name,
},
Spec: &v1.ServiceSpecArgs{
Selector: pulumi.StringMap{
"app": pulumi.String("redis"),
},
Ports: v1.ServicePortArray{
&v1.ServicePortArgs{
Port: pulumi.Int(6379),
TargetPort: pulumi.Int(6379),
},
},
},
}, pulumi.Provider(k8sProvider))
if err != nil {
return err
}
// Create application deployment
appDeployment, err := v1.NewDeployment(ctx, "app-deployment", &v1.DeploymentArgs{
Metadata: &v1.ObjectMetaArgs{
Name: pulumi.String("app"),
Namespace: namespace.Name,
Labels: pulumi.StringMap{
"app": pulumi.String("my-app"),
"tier": pulumi.String("frontend"),
},
},
Spec: &v1.DeploymentSpecArgs{
Replicas: pulumi.IntPtr(3),
Selector: &v1.LabelSelectorArgs{
MatchLabels: pulumi.StringMap{
"app": pulumi.String("my-app"),
},
},
Template: &v1.PodTemplateSpecArgs{
Metadata: &v1.ObjectMetaArgs{
Labels: pulumi.StringMap{
"app": pulumi.String("my-app"),
},
},
Spec: &v1.PodSpecArgs{
Containers: v1.ContainerArray{
&v1.ContainerArgs{
Name: pulumi.String("app"),
Image: pulumi.String("nginx:alpine"),
Ports: v1.ContainerPortArray{
&v1.ContainerPortArgs{
ContainerPort: pulumi.Int(80),
},
},
Env: v1.EnvVarArray{
&v1.EnvVarArgs{
Name: pulumi.String("ENVIRONMENT"),
Value: pulumi.String(environment),
},
},
Resources: &v1.ResourceRequirementsArgs{
Requests: pulumi.StringMap{
"memory": pulumi.String("64Mi"),
"cpu": pulumi.String("250m"),
},
Limits: pulumi.StringMap{
"memory": pulumi.String("128Mi"),
"cpu": pulumi.String("500m"),
},
},
ReadinessProbe: &v1.ProbeArgs{
HttpGet: &v1.HTTPGetActionArgs{
Path: pulumi.String("/"),
Port: pulumi.Int(80),
},
InitialDelaySeconds: pulumi.Int(5),
PeriodSeconds: pulumi.Int(10),
},
},
},
},
},
},
}, pulumi.Provider(k8sProvider))
if err != nil {
return err
}
// Create application service
appService, err := v1.NewService(ctx, "app-service", &v1.ServiceArgs{
Metadata: &v1.ObjectMetaArgs{
Name: pulumi.String("app-service"),
Namespace: namespace.Name,
},
Spec: &v1.ServiceSpecArgs{
Type: pulumi.String("LoadBalancer"),
Selector: pulumi.StringMap{
"app": pulumi.String("my-app"),
},
Ports: v1.ServicePortArray{
&v1.ServicePortArgs{
Port: pulumi.Int(80),
TargetPort: pulumi.Int(80),
},
},
},
}, pulumi.Provider(k8sProvider))
if err != nil {
return err
}
// Create Ingress for HTTP routing
appIngress, err := networkingv1.NewIngress(ctx, "app-ingress", &networkingv1.IngressArgs{
Metadata: &v1.ObjectMetaArgs{
Name: pulumi.String("app-ingress"),
Namespace: namespace.Name,
Annotations: pulumi.StringMap{
"kubernetes.io/ingress.class": pulumi.String("nginx"),
"cert-manager.io/cluster-issuer": pulumi.String("letsencrypt-prod"),
},
},
Spec: &networkingv1.IngressSpecArgs{
Tls: networkingv1.IngressTLSArray{
&networkingv1.IngressTLSArgs{
Hosts: pulumi.StringArray{
pulumi.String("app.example.com"),
},
SecretName: pulumi.String("app-tls"),
},
},
Rules: networkingv1.IngressRuleArray{
&networkingv1.IngressRuleArgs{
Host: pulumi.String("app.example.com"),
Http: &networkingv1.HTTPIngressRuleValueArgs{
Paths: networkingv1.HTTPIngressPathArray{
&networkingv1.HTTPIngressPathArgs{
Path: pulumi.String("/"),
PathType: pulumi.String("Prefix"),
Backend: &networkingv1.IngressBackendArgs{
Service: &networkingv1.IngressServiceBackendArgs{
Name: appService.Name,
Port: &networkingv1.ServiceBackendPortArgs{
Number: pulumi.Int(80),
},
},
},
},
},
},
},
},
},
}, pulumi.Provider(k8sProvider))
if err != nil {
return err
}
// Deploy Helm chart for monitoring (Prometheus)
prometheusChart, err := helmv3.NewRelease(ctx, "prometheus", &helmv3.ReleaseArgs{
Chart: pulumi.String("prometheus"),
Version: pulumi.String("25.8.0"),
Namespace: namespace.Name,
RepositoryOpts: &helmv3.RepositoryOptsArgs{
Repo: pulumi.String("https://prometheus-community.github.io/helm-charts"),
},
Values: pulumi.Map{
"server": pulumi.Map{
"persistentVolume": pulumi.Map{
"enabled": pulumi.Bool(false),
},
},
"alertmanager": pulumi.Map{
"enabled": pulumi.Bool(false),
},
},
}, pulumi.Provider(k8sProvider))
if err != nil {
return err
}
// Export outputs
ctx.Export("namespace_name", namespace.Name)
ctx.Export("redis_deployment_name", redisDeployment.Name)
ctx.Export("redis_service_name", redisService.Name)
ctx.Export("app_deployment_name", appDeployment.Name)
ctx.Export("app_service_name", appService.Name)
ctx.Export("app_load_balancer_ip", appService.Status.Apply(func(status *v1.ServiceStatus) *string {
if status.LoadBalancer != nil && len(status.LoadBalancer.Ingress) > 0 {
return status.LoadBalancer.Ingress[0].Ip
}
return pulumi.String("")
}))
ctx.Export("ingress_host", appIngress.Spec.Apply(func(spec *networkingv1.IngressSpec) string {
if len(spec.Rules) > 0 {
return *spec.Rules[0].Host
}
return ""
}))
ctx.Export("prometheus_release_name", prometheusChart.Name)
return nil
})
}
💻 Pulumi 多云基础设施 typescript
🔴 complex
⭐⭐⭐⭐⭐
使用 Pulumi 跨多个云提供商部署基础设施
⏱️ 45 min
🏷️ pulumi, multi-cloud, aws, azure, gcp, hybrid
Prerequisites:
Advanced Pulumi, Multiple cloud accounts, Cross-cloud networking
// Multi-Cloud Infrastructure with Pulumi
import * as pulumi from '@pulumi/pulumi';
import * as aws from '@pulumi/aws';
import * as azure from '@pulumi/azure-native';
import * as gcp from '@pulumi/gcp';
// Configuration
const config = new pulumi.Config();
const stackName = pulumi.getStack();
const environment = stackName === 'prod' ? 'production' : 'development';
// AWS Configuration
const awsRegion = config.get('awsRegion', 'us-west-2');
const awsProvider = new aws.Provider('aws', {
region: awsRegion,
});
// Azure Configuration
const azureLocation = config.get('azureLocation', 'East US');
const azureResourceGroupName = pulumi.interpolate `rg-pulumi-multi-${stackName}`;
const azureResourceGroup = new azure.resources.ResourceGroup('azure-rg', {
resourceGroupName: azureResourceGroupName,
location: azureLocation,
tags: {
environment,
managedBy: 'pulumi'
}
});
// GCP Configuration
const gcpConfig = new gcp.Provider('gcp', {
project: config.require('gcpProjectId'),
region: config.get('gcpRegion', 'us-central1'),
});
// AWS Infrastructure
const awsVpc = new aws.ec2.Vpc('aws-vpc', {
cidrBlock: '10.0.0.0/16',
enableDnsHostnames: true,
enableDnsSupport: true,
tags: {
Name: pulumi.interpolate `pulumi-multi-${stackName}`,
Environment: environment
}
}, { provider: awsProvider });
const awsSubnet = new aws.ec2.Subnet('aws-subnet', {
vpcId: awsVpc.id,
cidrBlock: '10.0.1.0/24',
availabilityZone: pulumi.interpolate `${awsRegion}a`,
mapPublicIpOnLaunch: true,
tags: {
Name: pulumi.interpolate `pulumi-multi-${stackName}-subnet`,
Environment: environment
}
}, { provider: awsProvider });
const awsSecurityGroup = new aws.ec2.SecurityGroup('aws-sg', {
vpcId: awsVpc.id,
ingress: [
{
protocol: 'tcp',
fromPort: 22,
toPort: 22,
cidrBlocks: ['0.0.0.0/0'],
description: 'SSH'
},
{
protocol: 'tcp',
fromPort: 80,
toPort: 80,
cidrBlocks: ['0.0.0.0/0'],
description: 'HTTP'
}
],
egress: [{
protocol: '-1',
fromPort: 0,
toPort: 0,
cidrBlocks: ['0.0.0.0/0']
}],
tags: {
Name: pulumi.interpolate `pulumi-multi-${stackName}-sg`,
Environment: environment
}
}, { provider: awsProvider });
// AWS Lambda function
const awsLambda = new aws.lambda.Function('aws-lambda', {
name: pulumi.interpolate `pulumi-multi-${stackName}-function`,
runtime: 'nodejs18.x',
handler: 'index.handler',
role: aws.iam.getRoleDocument('lambda-role-doc', {
assumeRolePolicy: JSON.stringify({
Version: '2012-10-17',
Statement: [{
Action: 'sts:AssumeRole',
Effect: 'Allow',
Principal: { Service: 'lambda.amazonaws.com' }
}]
})
}).then(doc => new aws.iam.Role('aws-lambda-role', {
assumeRolePolicy: doc.json,
name: pulumi.interpolate `pulumi-multi-${stackName}-lambda-role`
}, { provider: awsProvider }).arn),
code: new pulumi.asset.AssetArchive({
'index.js': new pulumi.asset.StringAsset(`
exports.handler = async (event) => {
return {
statusCode: 200,
body: JSON.stringify({
message: 'Hello from AWS Lambda!',
cloud: 'AWS',
region: process.env.AWS_REGION,
timestamp: new Date().toISOString()
})
};
};
`)
}),
environment: {
variables: {
ENVIRONMENT: environment
}
},
tags: {
Name: pulumi.interpolate `pulumi-multi-${stackName}-lambda`,
Environment: environment
}
}, { provider: awsProvider });
// Azure Infrastructure
const azureVirtualNetwork = new azure.network.VirtualNetwork('azure-vnet', {
virtualNetworkName: pulumi.interpolate `pulumi-multi-${stackName}-vnet`,
resourceGroupName: azureResourceGroup.name,
location: azureLocation,
addressSpace: {
addressPrefixes: ['10.1.0.0/16']
},
tags: {
environment,
managedBy: 'pulumi'
}
});
const azureSubnet = new azure.network.Subnet('azure-subnet', {
subnetName: pulumi.interpolate `pulumi-multi-${stackName}-subnet`,
resourceGroupName: azureResourceGroup.name,
virtualNetworkName: azureVirtualNetwork.name,
addressPrefix: '10.1.1.0/24',
privateEndpointNetworkPolicies: 'Disabled',
privateLinkServiceNetworkPolicies: 'Enabled'
});
const azureNetworkSecurityGroup = new azure.network.NetworkSecurityGroup('azure-nsg', {
networkSecurityGroupName: pulumi.interpolate `pulumi-multi-${stackName}-nsg`,
resourceGroupName: azureResourceGroup.name,
location: azureLocation,
securityRules: [
{
name: 'AllowSSH',
priority: 1000,
direction: 'Inbound',
access: 'Allow',
protocol: 'Tcp',
sourcePortRange: '*',
destinationPortRange: '22',
sourceAddressPrefix: '*',
destinationAddressPrefix: '*'
},
{
name: 'AllowHTTP',
priority: 1001,
direction: 'Inbound',
access: 'Allow',
protocol: 'Tcp',
sourcePortRange: '*',
destinationPortRange: '80',
sourceAddressPrefix: '*',
destinationAddressPrefix: '*'
}
]
});
// Azure Function App
const azureStorageAccount = new azure.storage.StorageAccount('azure-storage', {
accountName: pulumi.random.RandomString('storage-suffix', {
length: 8,
special: false,
upper: false
}).result.apply(suffix => `pulumi${suffix}`),
resourceGroupName: azureResourceGroup.name,
location: azureLocation,
kind: 'StorageV2',
sku: {
name: azure.storage.SkuName.Standard_LRS
},
tags: {
environment,
managedBy: 'pulumi'
}
});
const azureFunctionApp = new azure.web.WebApp('azure-function', {
name: pulumi.interpolate `pulumi-multi-${stackName}-function`,
resourceGroupName: azureResourceGroup.name,
location: azureLocation,
kind: 'functionapp',
serverFarmId: new azure.web.AppServicePlan('azure-app-service-plan', {
name: pulumi.interpolate `pulumi-multi-${stackName}-asp`,
resourceGroupName: azureResourceGroup.name,
location: azureLocation,
sku: {
name: azure.web.SkuName.Basic,
tier: azure.web.SkuTier.Basic,
size: 'B1'
},
kind: 'linux',
reserved: true
}).id,
siteConfig: {
linuxFxVersion: 'NODE|18-lts',
appSettings: [
{
name: 'WEBSITE_RUN_FROM_PACKAGE',
value: '1'
},
{
name: 'FUNCTIONS_WORKER_RUNTIME',
value: 'node'
},
{
name: 'ENVIRONMENT',
value: environment
},
{
name: 'AzureWebJobsStorage',
value: azureStorageAccount.primaryConnectionString
}
]
},
tags: {
environment,
managedBy: 'pulumi'
}
});
// GCP Infrastructure
const gcpVpcNetwork = new gcp.compute.Network('gcp-vpc', {
name: pulumi.interpolate `pulumi-multi-${stackName}-vnet`,
autoCreateSubnetworks: false,
description: pulumi.interpolate `VPC for Pulumi multi-cloud demo in ${environment}`,
routingMode: 'REGIONAL',
tags: {
environment,
managedBy: 'pulumi'
}
}, { provider: gcpConfig });
const gcpSubnet = new gcp.compute.Subnetwork('gcp-subnet', {
name: pulumi.interpolate `pulumi-multi-${stackName}-subnet`,
ipCidrRange: '10.2.1.0/24',
region: config.get('gcpRegion', 'us-central1'),
network: gcpVpcNetwork.id,
privateIpGoogleAccess: false,
tags: {
environment,
managedBy: 'pulumi'
}
}, { provider: gcpConfig });
const gcpFirewall = new gcp.compute.Firewall('gcp-firewall', {
name: pulumi.interpolate `pulumi-multi-${stackName}-fw`,
network: gcpVpcNetwork.id,
allow: [{
protocol: 'tcp',
ports: ['22', '80']
}],
sourceRanges: ['0.0.0.0/0'],
description: 'Allow SSH and HTTP traffic',
tags: {
environment,
managedBy: 'pulumi'
}
}, { provider: gcpConfig });
// GCP Cloud Function
const gcpBucketSuffix = pulumi.random.RandomString('gcp-bucket-suffix', {
length: 8,
special: false,
upper: false
}).result;
const gcpBucket = new gcp.storage.Bucket('gcp-function-bucket', {
name: gcpBucketSuffix.apply(suffix => `pulumi-multi-${stackName}-bucket-${suffix}`),
location: config.get('gcpRegion', 'US-CENTRAL1'),
forceDestroy: true,
uniformBucketLevelAccess: true,
tags: {
environment,
managedBy: 'pulumi'
}
}, { provider: gcpConfig });
const gcpFunctionArchive = new gcp.storage.BucketObject('gcp-function-zip', {
name: 'function.zip',
bucket: gcpBucket.name,
source: new pulumi.asset.AssetArchive({
'index.js': new pulumi.asset.StringAsset(`
exports.handler = async (req, res) => {
res.status(200).json({
message: 'Hello from GCP Cloud Function!',
cloud: 'GCP',
region: process.env.FUNCTION_REGION,
timestamp: new Date().toISOString()
});
};
`)
})
}, { provider: gcpConfig });
const gcpFunction = new gcp.cloudfunctions.Function('gcp-function', {
name: pulumi.interpolate `pulumi-multi-${stackName}-function`,
description: pulumi.interpolate `Pulumi multi-cloud demo function in ${environment}`,
runtime: 'nodejs18',
entryPoint: 'handler',
sourceArchiveBucket: gcpBucket.name,
sourceArchiveObject: gcpFunctionArchive.name,
triggerHttp: true,
availableMemoryMb: 256,
timeout: 60,
environmentVariables: {
ENVIRONMENT: environment
},
tags: {
environment,
managedBy: 'pulumi'
}
}, { provider: gcpConfig });
// Enable Cloud Function invocations
const gcpFunctionIAM = new gcp.cloudfunctions.FunctionIamPolicy('gcp-function-iam', {
region: gcpFunction.region,
cloudFunction: gcpFunction.name,
bindings: [{
role: 'roles/cloudfunctions.invoker',
members: ['allUsers']
}]
}, { provider: gcpConfig });
// Cross-Cloud Networking (VPN connections would go here)
// This is a simplified example - in production you'd set up VPN tunnels or Direct Connect
// Monitoring Integration (using a centralized monitoring solution)
const monitoringConfig = {
aws: {
lambdaName: awsLambda.name,
region: awsRegion
},
azure: {
functionName: azureFunctionApp.name,
resourceGroup: azureResourceGroup.name
},
gcp: {
functionName: gcpFunction.name,
region: config.get('gcpRegion', 'us-central1')
}
};
// Export outputs
export const awsInfrastructure = {
vpcId: awsVpc.id,
subnetId: awsSubnet.id,
lambdaFunctionName: awsLambda.name,
lambdaArn: awsLambda.arn
};
export const azureInfrastructure = {
resourceGroupName: azureResourceGroup.name,
vnetName: azureVirtualNetwork.name,
subnetName: azureSubnet.name,
functionName: azureFunctionApp.name,
functionUrl: azureFunctionApp.defaultHostName
};
export const gcpInfrastructure = {
vpcName: gcpVpcNetwork.name,
subnetName: gcpSubnet.name,
functionName: gcpFunction.name,
functionUrl: gcpFunction.httpsTriggerUrl
};
export const monitoringSetup = monitoringConfig;
// Additional exports for easy access
pulumi.export('aws_lambda_name', awsLambda.name);
pulumi.export('azure_function_name', azureFunctionApp.name);
pulumi.export('gcp_function_name', gcpFunction.name);
pulumi.export('gcp_function_url', gcpFunction.httpsTriggerUrl);
// Stack outputs for monitoring dashboard
pulumi.export('dashboard_config', pulumi.all([
awsLambda.name,
azureFunctionApp.name,
gcpFunction.name
]).apply(([awsName, azureName, gcpName]) => JSON.stringify({
environment,
services: {
aws: awsName,
azure: azureName,
gcp: gcpName
},
monitoring: {
enabled: true,
providers: ['cloudwatch', 'azure-monitor', 'cloud-monitoring']
}
})));