Created
March 26, 2025 10:09
-
-
Save Cmion/5baa5c9af43baffede0f5166d378fa5a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <reference path="./.sst/platform/config.d.ts" /> | |
import { readFileSync } from "node:fs"; | |
export default $config({ | |
app(input) { | |
return { | |
name: "hello-zero", | |
removal: input?.stage === "production" ? "retain" : "remove", | |
home: "aws", | |
providers: { | |
command: true, | |
"azure-native": { | |
version: "2.89.2", | |
subscriptionId: process.env.AZURE_SUBSCRIPTION_ID, | |
tenantId: process.env.AZURE_TENANT_ID, | |
location: "eastus2", | |
}, | |
}, | |
}; | |
}, | |
async run() { | |
const resourceGroup = new azurenative.resources.ResourceGroup( | |
"resource-group" | |
); | |
const storageAccount = new azurenative.storage.StorageAccount( | |
"storage-account", | |
{ | |
resourceGroupName: resourceGroup.name, | |
location: resourceGroup.location, | |
sku: { | |
name: azurenative.storage.SkuName.Standard_LRS, | |
}, | |
kind: azurenative.storage.Kind.StorageV2, | |
minimumTlsVersion: azurenative.storage.MinimumTlsVersion.TLS1_2, | |
allowBlobPublicAccess: false, | |
allowSharedKeyAccess: true, | |
defaultToOAuthAuthentication: false, | |
isHnsEnabled: true, | |
isSftpEnabled: true, | |
isLocalUserEnabled: true, | |
tags: { | |
"sst:stage": $app.stage, | |
"sst:app": $app.name, | |
}, | |
} | |
); | |
const storageAccountKey = azurenative.storage | |
.listStorageAccountKeysOutput({ | |
resourceGroupName: resourceGroup.name, | |
accountName: storageAccount.name, | |
}) | |
.keys.apply((keys) => keys[0].value); | |
const replicationContainer = new azurenative.storage.BlobContainer( | |
"replication-container", | |
{ | |
accountName: storageAccount.name, | |
publicAccess: azurenative.storage.PublicAccess.None, | |
resourceGroupName: resourceGroup.name, | |
} | |
); | |
const environment = new azurenative.app.ManagedEnvironment( | |
"app-environment", | |
{ | |
resourceGroupName: resourceGroup.name, | |
location: resourceGroup.location, | |
tags: { | |
"sst:stage": $app.stage, | |
"sst:app": $app.name, | |
}, | |
} | |
); | |
const tag = $dev | |
? `latest` | |
: JSON.parse( | |
readFileSync("./node_modules/@rocicorp/zero/package.json").toString() | |
).version.replace("+", "-"); | |
const image = `registry.hub.docker.com/rocicorp/zero:${tag}`; | |
const conn = new sst.Secret("PostgresConnectionString"); | |
const zeroAuthSecret = new sst.Secret("ZeroAuthSecret"); | |
const commonEnv = [ | |
{ name: "ZERO_LOG_LEVEL", value: "debug" }, | |
{ name: "ZERO_LITESTREAM_LOG_LEVEL", value: "debug" }, | |
{ name: "ZERO_UPSTREAM_DB", value: conn.value }, | |
{ name: "ZERO_CVR_DB", value: conn.value }, | |
{ name: "ZERO_CHANGE_DB", value: conn.value }, | |
{ name: "ZERO_REPLICA_FILE", value: "/tmp/sync-replica.db" }, | |
{ | |
name: "ZERO_AUTH_SECRET", | |
value: zeroAuthSecret.value, | |
}, | |
{ name: "ZERO_LITESTREAM_RESTORE_PARALLELISM", value: "64" }, | |
{ name: "ZERO_APP_ID", value: $app.stage }, | |
{ | |
name: "ZERO_LITESTREAM_BACKUP_URL", | |
value: $interpolate`abs://${storageAccount.name}@${replicationContainer.name}/backup`, | |
}, | |
{ | |
name: "LITESTREAM_AZURE_ACCOUNT_KEY", // Needed when using Azure Blob Storage (ABS) | |
value: storageAccountKey, | |
}, | |
]; | |
const replicationManager = new azurenative.app.ContainerApp( | |
"replication-manager", | |
{ | |
resourceGroupName: resourceGroup.name, | |
location: resourceGroup.location, | |
environmentId: environment.id, | |
configuration: { | |
ingress: { | |
external: false, | |
targetPort: 4849, | |
transport: azurenative.app.IngressTransportMethod.Auto, | |
}, | |
}, | |
template: { | |
containers: [ | |
{ | |
name: "rocicorp-zero", | |
image, | |
resources: { cpu: 0.5, memory: "1Gi" }, // Optimized for consumption pricing | |
env: [ | |
...commonEnv, | |
{ name: "ZERO_CHANGE_MAX_CONNS", value: "3" }, | |
{ name: "ZERO_NUM_SYNC_WORKERS", value: "0" }, | |
], | |
probes: [ | |
{ | |
httpGet: { | |
path: "/", | |
port: 4849, | |
}, | |
initialDelaySeconds: 30, | |
periodSeconds: 5, | |
type: azurenative.app.Type.Liveness, | |
}, | |
], | |
volumeMounts: [ | |
{ | |
mountPath: "/data", | |
volumeName: "volume", | |
}, | |
], | |
}, | |
], | |
volumes: [ | |
{ | |
name: "volume", | |
storageType: "EmptyDir", | |
}, | |
], | |
scale: { | |
maxReplicas: 2, | |
minReplicas: 1, | |
}, | |
}, | |
tags: { | |
"sst:stage": $app.stage, | |
"sst:app": $app.name, | |
}, | |
} | |
); | |
// Deploy your permissions | |
if (replicationManager) | |
new command.local.Command( | |
"zero-permission", | |
{ | |
dir: process.cwd() + "/apps/api", // Change this to your app path | |
environment: { | |
ZERO_UPSTREAM_DB: conn.value, | |
ZERO_APP_ID: $app.stage, | |
}, | |
create: "bun run zero-deploy", // Or npx zero-deploy-permissions | |
triggers: [Date.now()], | |
}, | |
{ | |
dependsOn: [replicationManager], | |
} | |
); | |
const viewSyncer = new azurenative.app.ContainerApp("view-syncer", { | |
resourceGroupName: resourceGroup.name, | |
location: resourceGroup.location, | |
environmentId: environment.id, | |
configuration: { | |
ingress: { | |
external: true, | |
targetPort: 4848, | |
transport: azurenative.app.IngressTransportMethod.Auto, | |
}, | |
}, | |
template: { | |
containers: [ | |
{ | |
name: "rocicorp-zero", | |
image, | |
resources: { cpu: 1, memory: "2Gi" }, | |
env: [ | |
...commonEnv, | |
...($dev | |
? [ | |
{ | |
name: "ZERO_NUM_SYNC_WORKERS", | |
value: "1", | |
}, | |
] | |
: [ | |
{ | |
name: "ZERO_CHANGE_STREAMER_URI", | |
value: $interpolate`https://${replicationManager.configuration.apply((c) => c?.ingress?.fqdn)}`, | |
}, | |
{ | |
name: "ZERO_CVR_MAX_CONNS", | |
value: "10", | |
}, | |
{ name: "ZERO_UPSTREAM_MAX_CONNS", value: "10" }, | |
]), | |
], | |
probes: [ | |
{ | |
httpGet: { | |
path: "/", | |
port: 4848, | |
scheme: "HTTP", | |
}, | |
initialDelaySeconds: 30, | |
periodSeconds: 5, | |
type: azurenative.app.Type.Liveness, | |
}, | |
], | |
volumeMounts: [ | |
{ | |
mountPath: "/data", | |
volumeName: "volume", | |
}, | |
], | |
}, | |
], | |
volumes: [ | |
{ | |
name: "volume", | |
storageType: "EmptyDir", | |
}, | |
], | |
scale: { | |
maxReplicas: 4, | |
minReplicas: 1, | |
}, | |
}, | |
tags: { | |
"sst:stage": $app.stage, | |
"sst:app": $app.name, | |
}, | |
}); | |
return { | |
viewSyncerURL: viewSyncer.configuration?.ingress?.fqdn, | |
}; | |
}, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment