diff --git a/openvidu-deployment/CHANGELOG.md b/openvidu-deployment/CHANGELOG.md index 862c12d23..ea17a5c68 100644 --- a/openvidu-deployment/CHANGELOG.md +++ b/openvidu-deployment/CHANGELOG.md @@ -74,6 +74,40 @@ in the [openvidu-oracle](https://github.com/OpenVidu/openvidu-oracle) and - With autoscaling, an unhealthy Media Node is tagged so the autoscaler deletes it and creates a new one. With a fixed number of Media Nodes, the Droplet is rebuilt in place. +### Improved + +#### All clouds + +- The single node and the Master Nodes get a 200 GB disk by default on every cloud where the template sets + its size. Azure and Google Cloud raise it from 100 GB (single node, Elastic Master Node and High + Availability Master Nodes), as do the High Availability Master Nodes on AWS and the Elastic and High + Availability Master Nodes on Oracle Cloud. Oracle Cloud single node, which used the size of the image + (about 47 GB), now sets 200 GB. AWS single node and Elastic Master Node already had 200 GB, and on + DigitalOcean the disk comes with the Droplet size. On Google Cloud and Oracle Cloud single node and the + Google Cloud Elastic Master Node, an existing deployment keeps its disk when the template is applied again. + Where the size is a parameter, set it to 100 when you apply the new template to an existing deployment + (`masterNodesDiskSize` on Google Cloud, `masterNodeDiskSize` on Oracle Cloud): Google Cloud recreates a + Master Node whose disk size changes. +- Parameter names are the same on every Terraform and Bicep template. The old names still work and take + precedence when set, but they are deprecated and will be removed in a future release: + - Google Cloud and Oracle Cloud single node: `RTCEngine` is now `rtcEngine`, as in their Elastic and High + Availability templates and on Azure and DigitalOcean. + - Google Cloud and DigitalOcean High Availability: `masterNodesInstanceType` is now + `masterNodeInstanceType`, as in every Elastic template and in Azure High Availability. + +#### Google Cloud + +- Every machine boots the latest Ubuntu 24.04 image (the `ubuntu-2404-lts` image family), as on the other + clouds. Before, the templates were pinned to an image from December 2024. An existing single node or Master + Node is not recreated when a newer image is published. The Media Nodes move to the image family once: the + first time the new template is applied to an existing Elastic or High Availability deployment, its Media + Nodes are replaced. + +#### Oracle Cloud + +- Single node defaults to 2 OCPUs and 8 GB of memory, the size of its own Elastic Master Node and of the + 4 vCPU and 8 GB machines of AWS and DigitalOcean. Before, it had 4 OCPUs with only 4 GB of memory. + ### Fixed #### All clouds @@ -104,3 +138,17 @@ in the [openvidu-oracle](https://github.com/OpenVidu/openvidu-oracle) and A redeploy still cannot set the fixed, minimum or maximum number of Media Nodes below the Media Nodes running (`UnsupportedCapacity`); the administration documentation describes how to remove them first. +- Single node and Elastic: the network security group still allowed port 9000 (MinIO) from the Internet. + MinIO does not run in Azure deployments, which store recordings and application data in Azure Blob Storage, + and the other clouds have kept this port closed since 3.9.0. The rule is removed. + +#### Google Cloud + +- Single node: the documentation names the media engine variable `rtcEngine`, but the template declared + `RTCEngine`, so a value set as documented was not applied. Both names work now. + +#### DigitalOcean + +- Elastic and High Availability: the OpenVidu v2 compatibility module (`v2compatibility`) was not enabled by + default, unlike on every other cloud and on DigitalOcean's Professional single node. It is now enabled by + default. diff --git a/openvidu-deployment/community/singlenode/azure/cf-openvidu-singlenode.bicep b/openvidu-deployment/community/singlenode/azure/cf-openvidu-singlenode.bicep index 490de621b..8aea4d63a 100644 --- a/openvidu-deployment/community/singlenode/azure/cf-openvidu-singlenode.bicep +++ b/openvidu-deployment/community/singlenode/azure/cf-openvidu-singlenode.bicep @@ -747,7 +747,7 @@ resource openviduServer 'Microsoft.Compute/virtualMachines@2023-09-01' = { managedDisk: { storageAccountType: openviduVMSettings.osDiskType } - diskSizeGB: 100 + diskSizeGB: 200 } imageReference: openviduVMSettings.ubuntuOSVersion } @@ -955,19 +955,6 @@ resource webServerSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-11 direction: 'Inbound' } } - { - name: 'MinIO' - properties: { - protocol: 'Tcp' - sourceAddressPrefix: '*' - sourcePortRange: '*' - destinationAddressPrefix: '*' - destinationPortRange: '9000' - access: 'Allow' - priority: 170 - direction: 'Inbound' - } - } { name: 'WebRTC_traffic_UDP' properties: { diff --git a/openvidu-deployment/community/singlenode/azure/cf-openvidu-singlenode.json b/openvidu-deployment/community/singlenode/azure/cf-openvidu-singlenode.json index 29501d785..0d296dbef 100644 --- a/openvidu-deployment/community/singlenode/azure/cf-openvidu-singlenode.json +++ b/openvidu-deployment/community/singlenode/azure/cf-openvidu-singlenode.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.46.1.21595", - "templateHash": "3312405466108841843" + "templateHash": "11383011699784191045" } }, "parameters": { @@ -261,7 +261,7 @@ "managedDisk": { "storageAccountType": "[variables('openviduVMSettings').osDiskType]" }, - "diskSizeGB": 100 + "diskSizeGB": 200 }, "imageReference": "[variables('openviduVMSettings').ubuntuOSVersion]" }, @@ -472,19 +472,6 @@ "direction": "Inbound" } }, - { - "name": "MinIO", - "properties": { - "protocol": "Tcp", - "sourceAddressPrefix": "*", - "sourcePortRange": "*", - "destinationAddressPrefix": "*", - "destinationPortRange": "9000", - "access": "Allow", - "priority": 170, - "direction": "Inbound" - } - }, { "name": "WebRTC_traffic_UDP", "properties": { diff --git a/openvidu-deployment/community/singlenode/gcp/tf-gpc-openvidu-singlenode.tf b/openvidu-deployment/community/singlenode/gcp/tf-gpc-openvidu-singlenode.tf index d18bcb414..53cb75f36 100644 --- a/openvidu-deployment/community/singlenode/gcp/tf-gpc-openvidu-singlenode.tf +++ b/openvidu-deployment/community/singlenode/gcp/tf-gpc-openvidu-singlenode.tf @@ -89,7 +89,7 @@ locals { is_arm_instance = startswith(var.instanceType, "c4a-") || startswith(var.instanceType, "t2a-") || startswith(var.instanceType, "n4a-") || startswith(var.instanceType, "a4x-") yq_arch = local.is_arm_instance ? "arm64" : "amd64" - ubuntu_image = local.is_arm_instance ? "ubuntu-os-cloud/ubuntu-2404-noble-arm64-v20241219" : "ubuntu-os-cloud/ubuntu-2404-noble-amd64-v20241219" + ubuntu_image = local.is_arm_instance ? "ubuntu-os-cloud/ubuntu-2404-lts-arm64" : "ubuntu-os-cloud/ubuntu-2404-lts-amd64" # C4A (Axion) does not support pd-standard boot disks — it requires Hyperdisk. # Mirror the pro/elastic template's logic so ARM singlenode deploys succeed. @@ -107,11 +107,17 @@ resource "google_compute_instance" "openvidu_server" { boot_disk { initialize_params { image = local.ubuntu_image - size = 100 + size = 200 type = local.is_c4a_instance ? "hyperdisk-balanced" : "pd-standard" } } + # The image family moves to each new Ubuntu 24.04 build and the disk size can change between + # releases: both apply to new deployments only, so a re-apply never recreates this VM. + lifecycle { + ignore_changes = [boot_disk[0].initialize_params[0].image, boot_disk[0].initialize_params[0].size] + } + network_interface { network = "default" access_config { diff --git a/openvidu-deployment/pro/elastic/aws/cf-openvidu-elastic.yaml b/openvidu-deployment/pro/elastic/aws/cf-openvidu-elastic.yaml index 09df620da..5261322e8 100644 --- a/openvidu-deployment/pro/elastic/aws/cf-openvidu-elastic.yaml +++ b/openvidu-deployment/pro/elastic/aws/cf-openvidu-elastic.yaml @@ -2134,7 +2134,7 @@ Resources: fi # Get Master Node private IP - MASTER_NODE_IP=${OpenViduMasterNode.PrivateIp} + MASTER_NODE_PRIVATE_IP=${OpenViduMasterNode.PrivateIp} # Download first: sh <(curl ...) would silently run an empty script on a transient curl failure INSTALLER_SCRIPT="/tmp/install_ov_media_node.sh" @@ -2152,7 +2152,7 @@ Resources: "--environment=aws" "--deployment-type=elastic" "--node-role='media-node'" - "--master-node-private-ip=$MASTER_NODE_IP" + "--master-node-private-ip=$MASTER_NODE_PRIVATE_IP" "--private-ip=$PRIVATE_IP" "--redis-password=$REDIS_PASSWORD" ) @@ -2547,10 +2547,10 @@ Resources: /usr/local/bin/install.sh || ov_media_bootstrap_failed "install.sh failed" # Wait for the master node to be healthy before starting (bounded: up to 1800s at 5s) - MASTER_NODE_IP=${OpenViduMasterNode.PrivateIp} + MASTER_NODE_PRIVATE_IP=${OpenViduMasterNode.PrivateIp} MASTER_HEALTHY=false for i in $(seq 1 360); do - if curl -sf "http://$MASTER_NODE_IP:7880/health/caddy" >/dev/null 2>&1; then + if curl -sf "http://$MASTER_NODE_PRIVATE_IP:7880/health/caddy" >/dev/null 2>&1; then MASTER_HEALTHY=true break fi diff --git a/openvidu-deployment/pro/elastic/azure/cf-openvidu-elastic.bicep b/openvidu-deployment/pro/elastic/azure/cf-openvidu-elastic.bicep index 2e1e9564f..b4ec19901 100644 --- a/openvidu-deployment/pro/elastic/azure/cf-openvidu-elastic.bicep +++ b/openvidu-deployment/pro/elastic/azure/cf-openvidu-elastic.bicep @@ -893,7 +893,7 @@ resource openviduMasterNode 'Microsoft.Compute/virtualMachines@2023-09-01' = { managedDisk: { storageAccountType: masterNodeVMSettings.osDiskType } - diskSizeGB: 100 + diskSizeGB: 200 } imageReference: masterNodeVMSettings.ubuntuOSVersion } @@ -959,11 +959,10 @@ set -e DOMAIN=$(az keyvault secret show --vault-name ${keyVaultName} --name DOMAIN-NAME --query value -o tsv) OPENVIDU_PRO_LICENSE=$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-PRO-LICENSE --query value -o tsv) REDIS_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name REDIS-PASSWORD --query value -o tsv) -ENABLED_MODULES=$(az keyvault secret show --vault-name ${keyVaultName} --name ENABLED-MODULES --query value -o tsv) OPENVIDU_VERSION="$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-VERSION --query value -o tsv)" # Get Master Node private IP -MASTER_NODE_IP=${privateIPMasterNode} +MASTER_NODE_PRIVATE_IP=${privateIPMasterNode} # Download to a file first: process substitution would silently run an empty script on a transient curl failure INSTALLER_SCRIPT="/tmp/install_ov_media_node.sh" @@ -983,9 +982,8 @@ COMMON_ARGS=( "--environment=azure" "--deployment-type=elastic" "--node-role='media-node'" - "--master-node-private-ip=$MASTER_NODE_IP" + "--master-node-private-ip=$MASTER_NODE_PRIVATE_IP" "--private-ip=$PRIVATE_IP" - "--enabled-modules='$ENABLED_MODULES'" "--redis-password=$REDIS_PASSWORD" ) # Construct the final command with all arguments @@ -1852,19 +1850,6 @@ resource openviduMasterNodeNSG 'Microsoft.Network/networkSecurityGroups@2023-11- direction: 'Inbound' } } - { - name: 'MinIO' - properties: { - protocol: 'Tcp' - sourceAddressPrefix: '*' - sourcePortRange: '*' - destinationAddressPrefix: '*' - destinationPortRange: '9000' - access: 'Allow' - priority: 140 - direction: 'Inbound' - } - } ] } } diff --git a/openvidu-deployment/pro/elastic/azure/cf-openvidu-elastic.json b/openvidu-deployment/pro/elastic/azure/cf-openvidu-elastic.json index 0e09181f4..087d779a8 100644 --- a/openvidu-deployment/pro/elastic/azure/cf-openvidu-elastic.json +++ b/openvidu-deployment/pro/elastic/azure/cf-openvidu-elastic.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.46.1.21595", - "templateHash": "12314273468008882970" + "templateHash": "5733974944942002101" } }, "parameters": { @@ -286,7 +286,7 @@ "base64check_app_readyMaster": "[base64(variables('check_app_readyScriptMaster'))]", "base64restartMaster": "[base64(variables('restartScriptMaster'))]", "userDataTemplateMasterNode": "#!/bin/bash\nset -eu -o pipefail\n\n# Introduce the scripts in the instance\n# install.sh\necho ${base64install} | base64 -d > /usr/local/bin/install.sh\nchmod +x /usr/local/bin/install.sh\n\n# after_install.sh\necho ${base64after_install} | base64 -d > /usr/local/bin/after_install.sh\nchmod +x /usr/local/bin/after_install.sh\n\n# update_config_from_secret.sh\necho ${base64update_config_from_secret} | base64 -d > /usr/local/bin/update_config_from_secret.sh\nchmod +x /usr/local/bin/update_config_from_secret.sh\n\n# update_secret_from_config.sh\necho ${base64update_secret_from_config} | base64 -d > /usr/local/bin/update_secret_from_config.sh\nchmod +x /usr/local/bin/update_secret_from_config.sh\n\n# get_value_from_config.sh\necho ${base64get_value_from_config} | base64 -d > /usr/local/bin/get_value_from_config.sh\nchmod +x /usr/local/bin/get_value_from_config.sh\n\n# store_secret.sh\necho ${base64store_secret} | base64 -d > /usr/local/bin/store_secret.sh\nchmod +x /usr/local/bin/store_secret.sh\n\n# get_public_ip.sh\necho ${base64get_public_ip} | base64 -d > /usr/local/bin/get_public_ip.sh\nchmod +x /usr/local/bin/get_public_ip.sh\n\n# check_app_ready.sh\necho ${base64check_app_ready} | base64 -d > /usr/local/bin/check_app_ready.sh\nchmod +x /usr/local/bin/check_app_ready.sh\n\n# restart.sh\necho ${base64restart} | base64 -d > /usr/local/bin/restart.sh\nchmod +x /usr/local/bin/restart.sh\n\necho ${base64config_blobStorage} | base64 -d > /usr/local/bin/config_blobStorage.sh\nchmod +x /usr/local/bin/config_blobStorage.sh\n\n# Install azure cli\nAZURE_CLI_VERSION=2.90.0\napt-get install -y apt-transport-https ca-certificates gnupg lsb-release\ncurl -sLS https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /etc/apt/trusted.gpg.d/microsoft.gpg\necho \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main\" | tee /etc/apt/sources.list.d/azure-cli.list\napt-get update\napt-get install -y azure-cli=${AZURE_CLI_VERSION}-1~$(lsb_release -cs)\n\naz login --identity --allow-no-subscriptions\n\necho \"DPkg::Lock::Timeout \\\"-1\\\";\" > /etc/apt/apt.conf.d/99timeout\n\nexport HOME=\"/root\"\n\n# Install OpenVidu\n/usr/local/bin/install.sh || { echo \"[OpenVidu] error installing OpenVidu\"; exit 1; }\n\n#Config blob storage\n/usr/local/bin/config_blobStorage.sh || { echo \"[OpenVidu] error configuring Blob Storage\"; exit 1; }\n\n# Start OpenVidu\nsystemctl start openvidu || { echo \"[OpenVidu] error starting OpenVidu\"; exit 1; }\n\n# Update shared secret\n/usr/local/bin/after_install.sh || { echo \"[OpenVidu] error updating shared secret\"; exit 1; }\n\n# Launch on reboot\necho \"@reboot /usr/local/bin/restart.sh >> /var/log/openvidu-restart.log\" 2>&1 | crontab\n\n# check_app_ready.sh internally caps its wait at 1200s\n/usr/local/bin/check_app_ready.sh || { echo \"[OpenVidu] master node did not become healthy\"; exit 1; }\n\naz keyvault secret set --vault-name ${keyVaultName} --name FINISH-MASTER-NODE --value \"true\"\n\nset +e\naz storage blob upload --account-name ${storageAccountName} --container-name automation-locks --name lock.txt --file /dev/null --auth-mode key\nset -e\n", - "installScriptTemplateMedia": "#!/bin/bash\nset -e\nDOMAIN=\n\n# Install dependencies\necho \"DPkg::Lock::Timeout \\\"-1\\\";\" > /etc/apt/apt.conf.d/99timeout\n\napt-get update && apt-get install -y \\\n curl \\\n unzip \\\n jq \\\n wget\n\n# Get own private IP\nPRIVATE_IP=$(curl -H Metadata:true --noproxy \"*\" \"http://169.254.169.254/metadata/instance/network/interface/0/ipv4/ipAddress/0/privateIpAddress?api-version=2017-08-01&format=text\")\n\n# Gate 1: wait for master secrets before installing\nWAIT_INTERVAL=5\nMAX_RETRIES=360\nRETRIES=0\nset +e\nwhile true; do\n ALL_SECRETS_GENERATED=$(az keyvault secret show --vault-name ${keyVaultName} --name ALL-SECRETS-GENERATED --query value -o tsv 2>/dev/null)\n if [ \"$ALL_SECRETS_GENERATED\" == \"true\" ]; then\n break\n fi\n RETRIES=$((RETRIES + 1))\n if [ $RETRIES -ge $MAX_RETRIES ]; then\n echo \"[OpenVidu] timed out after 30 min waiting for ALL-SECRETS-GENERATED\"\n exit 1\n fi\n sleep $WAIT_INTERVAL\ndone\nset -e\n# Get current shared secret\nDOMAIN=$(az keyvault secret show --vault-name ${keyVaultName} --name DOMAIN-NAME --query value -o tsv)\nOPENVIDU_PRO_LICENSE=$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-PRO-LICENSE --query value -o tsv)\nREDIS_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name REDIS-PASSWORD --query value -o tsv)\nENABLED_MODULES=$(az keyvault secret show --vault-name ${keyVaultName} --name ENABLED-MODULES --query value -o tsv)\nOPENVIDU_VERSION=\"$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-VERSION --query value -o tsv)\"\n\n# Get Master Node private IP\nMASTER_NODE_IP=${privateIPMasterNode}\n\n# Download to a file first: process substitution would silently run an empty script on a transient curl failure\nINSTALLER_SCRIPT=\"/tmp/install_ov_media_node.sh\"\ncurl -fsSL --retry 8 --retry-all-errors --retry-delay 5 -o \"$INSTALLER_SCRIPT\" \"https://get.openvidu.io/pro/elastic/$OPENVIDU_VERSION/install_ov_media_node.sh\"\nif [ ! -s \"$INSTALLER_SCRIPT\" ]; then\n echo \"[OpenVidu] failed to download the media node installer script\"\n exit 1\nfi\n\n# Base command\nINSTALL_COMMAND=\"sh $INSTALLER_SCRIPT\"\n\n# Common arguments\nCOMMON_ARGS=(\n \"--no-tty\"\n \"--install\"\n \"--environment=azure\"\n \"--deployment-type=elastic\"\n \"--node-role='media-node'\"\n \"--master-node-private-ip=$MASTER_NODE_IP\"\n \"--private-ip=$PRIVATE_IP\"\n \"--enabled-modules='$ENABLED_MODULES'\"\n \"--redis-password=$REDIS_PASSWORD\"\n)\n# Construct the final command with all arguments\nFINAL_COMMAND=\"$INSTALL_COMMAND $(printf \"%s \" \"${COMMON_ARGS[@]}\")\"\n\n# Install OpenVidu\nexec bash -c \"$FINAL_COMMAND\"\n", + "installScriptTemplateMedia": "#!/bin/bash\nset -e\nDOMAIN=\n\n# Install dependencies\necho \"DPkg::Lock::Timeout \\\"-1\\\";\" > /etc/apt/apt.conf.d/99timeout\n\napt-get update && apt-get install -y \\\n curl \\\n unzip \\\n jq \\\n wget\n\n# Get own private IP\nPRIVATE_IP=$(curl -H Metadata:true --noproxy \"*\" \"http://169.254.169.254/metadata/instance/network/interface/0/ipv4/ipAddress/0/privateIpAddress?api-version=2017-08-01&format=text\")\n\n# Gate 1: wait for master secrets before installing\nWAIT_INTERVAL=5\nMAX_RETRIES=360\nRETRIES=0\nset +e\nwhile true; do\n ALL_SECRETS_GENERATED=$(az keyvault secret show --vault-name ${keyVaultName} --name ALL-SECRETS-GENERATED --query value -o tsv 2>/dev/null)\n if [ \"$ALL_SECRETS_GENERATED\" == \"true\" ]; then\n break\n fi\n RETRIES=$((RETRIES + 1))\n if [ $RETRIES -ge $MAX_RETRIES ]; then\n echo \"[OpenVidu] timed out after 30 min waiting for ALL-SECRETS-GENERATED\"\n exit 1\n fi\n sleep $WAIT_INTERVAL\ndone\nset -e\n# Get current shared secret\nDOMAIN=$(az keyvault secret show --vault-name ${keyVaultName} --name DOMAIN-NAME --query value -o tsv)\nOPENVIDU_PRO_LICENSE=$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-PRO-LICENSE --query value -o tsv)\nREDIS_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name REDIS-PASSWORD --query value -o tsv)\nOPENVIDU_VERSION=\"$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-VERSION --query value -o tsv)\"\n\n# Get Master Node private IP\nMASTER_NODE_PRIVATE_IP=${privateIPMasterNode}\n\n# Download to a file first: process substitution would silently run an empty script on a transient curl failure\nINSTALLER_SCRIPT=\"/tmp/install_ov_media_node.sh\"\ncurl -fsSL --retry 8 --retry-all-errors --retry-delay 5 -o \"$INSTALLER_SCRIPT\" \"https://get.openvidu.io/pro/elastic/$OPENVIDU_VERSION/install_ov_media_node.sh\"\nif [ ! -s \"$INSTALLER_SCRIPT\" ]; then\n echo \"[OpenVidu] failed to download the media node installer script\"\n exit 1\nfi\n\n# Base command\nINSTALL_COMMAND=\"sh $INSTALLER_SCRIPT\"\n\n# Common arguments\nCOMMON_ARGS=(\n \"--no-tty\"\n \"--install\"\n \"--environment=azure\"\n \"--deployment-type=elastic\"\n \"--node-role='media-node'\"\n \"--master-node-private-ip=$MASTER_NODE_PRIVATE_IP\"\n \"--private-ip=$PRIVATE_IP\"\n \"--redis-password=$REDIS_PASSWORD\"\n)\n# Construct the final command with all arguments\nFINAL_COMMAND=\"$INSTALL_COMMAND $(printf \"%s \" \"${COMMON_ARGS[@]}\")\"\n\n# Install OpenVidu\nexec bash -c \"$FINAL_COMMAND\"\n", "stopMediaNodeParams": { "subscriptionId": "[subscription().subscriptionId]", "resourceGroupName": "[resourceGroup().name]", @@ -392,7 +392,7 @@ "managedDisk": { "storageAccountType": "[variables('masterNodeVMSettings').osDiskType]" }, - "diskSizeGB": 100 + "diskSizeGB": 200 }, "imageReference": "[variables('masterNodeVMSettings').ubuntuOSVersion]" }, @@ -811,19 +811,6 @@ "priority": 130, "direction": "Inbound" } - }, - { - "name": "MinIO", - "properties": { - "protocol": "Tcp", - "sourceAddressPrefix": "*", - "sourcePortRange": "*", - "destinationAddressPrefix": "*", - "destinationPortRange": "9000", - "access": "Allow", - "priority": 140, - "direction": "Inbound" - } } ] } diff --git a/openvidu-deployment/pro/elastic/gcp/tf-gpc-openvidu-elastic.tf b/openvidu-deployment/pro/elastic/gcp/tf-gpc-openvidu-elastic.tf index ca8fe421a..6e2b98a1e 100644 --- a/openvidu-deployment/pro/elastic/gcp/tf-gpc-openvidu-elastic.tf +++ b/openvidu-deployment/pro/elastic/gcp/tf-gpc-openvidu-elastic.tf @@ -144,7 +144,7 @@ locals { is_arm_instance = startswith(var.masterNodeInstanceType, "c4a-") || startswith(var.masterNodeInstanceType, "t2a-") || startswith(var.masterNodeInstanceType, "n4a-") || startswith(var.masterNodeInstanceType, "a4x-") yq_arch = local.is_arm_instance ? "arm64" : "amd64" - ubuntu_image = local.is_arm_instance ? "ubuntu-os-cloud/ubuntu-2404-noble-arm64-v20241219" : "ubuntu-os-cloud/ubuntu-2404-noble-amd64-v20241219" + ubuntu_image = local.is_arm_instance ? "ubuntu-os-cloud/ubuntu-2404-lts-arm64" : "ubuntu-os-cloud/ubuntu-2404-lts-amd64" is_c4a_instance = startswith(var.masterNodeInstanceType, "c4a-") } @@ -159,11 +159,20 @@ resource "google_compute_instance" "openvidu_master_node" { boot_disk { initialize_params { image = local.ubuntu_image - size = 100 + size = 200 type = local.is_c4a_instance ? "hyperdisk-balanced" : "pd-standard" } } + # Keep existing Master Nodes when a newer Ubuntu 24.04 image is published or when the + # default boot disk size changes, so a re-apply never recreates a running Master Node. + lifecycle { + ignore_changes = [ + boot_disk[0].initialize_params[0].image, + boot_disk[0].initialize_params[0].size, + ] + } + network_interface { network = "default" access_config { @@ -207,7 +216,7 @@ resource "google_compute_instance" "openvidu_master_node" { locals { is_arm_instance_media = startswith(var.mediaNodeInstanceType, "c4a-") || startswith(var.mediaNodeInstanceType, "t2a-") || startswith(var.mediaNodeInstanceType, "n4a-") || startswith(var.mediaNodeInstanceType, "a4x-") - ubuntu_image_media = local.is_arm_instance_media ? "ubuntu-os-cloud/ubuntu-2404-noble-arm64-v20241219" : "ubuntu-os-cloud/ubuntu-2404-noble-amd64-v20241219" + ubuntu_image_media = local.is_arm_instance_media ? "ubuntu-os-cloud/ubuntu-2404-lts-arm64" : "ubuntu-os-cloud/ubuntu-2404-lts-amd64" is_c4a_instance_media = startswith(var.mediaNodeInstanceType, "c4a-") } diff --git a/openvidu-deployment/pro/ha/aws/cf-openvidu-ha.yaml b/openvidu-deployment/pro/ha/aws/cf-openvidu-ha.yaml index 7dad8bddb..1773b65b7 100644 --- a/openvidu-deployment/pro/ha/aws/cf-openvidu-ha.yaml +++ b/openvidu-deployment/pro/ha/aws/cf-openvidu-ha.yaml @@ -1066,7 +1066,7 @@ Parameters: MasterNodesDiskSize: Description: Size of the disk in GB Type: Number - Default: 100 + Default: 200 MinValue: 50 ConstraintDescription: The disk size must be at least 50 GB diff --git a/openvidu-deployment/pro/ha/azure/cf-openvidu-ha.bicep b/openvidu-deployment/pro/ha/azure/cf-openvidu-ha.bicep index 233163d38..c03a3e58e 100644 --- a/openvidu-deployment/pro/ha/azure/cf-openvidu-ha.bicep +++ b/openvidu-deployment/pro/ha/azure/cf-openvidu-ha.bicep @@ -50,7 +50,7 @@ param initialMeetApiKey string = '' param masterNodeInstanceType string = 'Standard_B4s' @description('Size of the disk in GB') -param masterNodesDiskSize int = 100 +param masterNodesDiskSize int = 200 @description('Specifies the VM size for your OpenVidu Media Nodes. You can use any valid Azure VM size (e.g., Standard_B4s, Standard_D4s_v5, Standard_E4ps_v5). See https://learn.microsoft.com/en-us/azure/virtual-machines/sizes for available sizes.') param mediaNodeInstanceType string = 'Standard_B4s' @@ -1353,7 +1353,6 @@ MASTER_NODE_3_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} MASTER_NODE_4_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-4-PRIVATE-IP --query value -o tsv) MASTER_NODE_PRIVATE_IP_LIST="$MASTER_NODE_1_PRIVATE_IP,$MASTER_NODE_2_PRIVATE_IP,$MASTER_NODE_3_PRIVATE_IP,$MASTER_NODE_4_PRIVATE_IP" REDIS_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name REDIS-PASSWORD --query value -o tsv) -ENABLED_MODULES=$(az keyvault secret show --vault-name ${keyVaultName} --name ENABLED-MODULES --query value -o tsv) OPENVIDU_VERSION=$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-VERSION --query value -o tsv) # Download first: sh <(curl ...) would silently run an empty script on a transient curl failure @@ -1376,7 +1375,6 @@ COMMON_ARGS=( "--node-role='media-node'" "--master-node-private-ip-list=$MASTER_NODE_PRIVATE_IP_LIST" "--private-ip=$PRIVATE_IP" -"--enabled-modules='$ENABLED_MODULES'" "--redis-password=$REDIS_PASSWORD" ) diff --git a/openvidu-deployment/pro/ha/azure/cf-openvidu-ha.json b/openvidu-deployment/pro/ha/azure/cf-openvidu-ha.json index f6f1ac547..41b0efd8c 100644 --- a/openvidu-deployment/pro/ha/azure/cf-openvidu-ha.json +++ b/openvidu-deployment/pro/ha/azure/cf-openvidu-ha.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.46.1.21595", - "templateHash": "1734713128178491421" + "templateHash": "128203215953929559" } }, "parameters": { @@ -96,7 +96,7 @@ }, "masterNodesDiskSize": { "type": "int", - "defaultValue": 100, + "defaultValue": 200, "metadata": { "description": "Size of the disk in GB" } @@ -262,7 +262,7 @@ "base64check_app_readyMaster": "[base64(variables('check_app_readyScriptMaster'))]", "base64restartMaster": "[base64(variables('restartScriptMaster'))]", "userDataTemplateMasterNode": "#!/bin/bash -x\nset -eu -o pipefail\n\n# Introduce the scripts in the instance\n# install.sh\necho ${base64install} | base64 -d > /usr/local/bin/install.sh\nchmod +x /usr/local/bin/install.sh\n\n# after_install.sh\necho ${base64after_install} | base64 -d > /usr/local/bin/after_install.sh\nchmod +x /usr/local/bin/after_install.sh\n\n# get_public_ip.sh\necho ${base64get_public_ip} | base64 -d > /usr/local/bin/get_public_ip.sh\nchmod +x /usr/local/bin/get_public_ip.sh\n\n# update_config_from_secret.sh\necho ${base64update_config_from_secret} | base64 -d > /usr/local/bin/update_config_from_secret.sh\nchmod +x /usr/local/bin/update_config_from_secret.sh\n\n# update_secret_from_config.sh\necho ${base64update_secret_from_config} | base64 -d > /usr/local/bin/update_secret_from_config.sh\nchmod +x /usr/local/bin/update_secret_from_config.sh\n\n# get_value_from_config.sh\necho ${base64get_value_from_config} | base64 -d > /usr/local/bin/get_value_from_config.sh\nchmod +x /usr/local/bin/get_value_from_config.sh\n\n# store_secret.sh\necho ${base64store_secret} | base64 -d > /usr/local/bin/store_secret.sh\nchmod +x /usr/local/bin/store_secret.sh\n\n# check_app_ready.sh\necho ${base64check_app_ready} | base64 -d > /usr/local/bin/check_app_ready.sh\nchmod +x /usr/local/bin/check_app_ready.sh\n\n# restart.sh\necho ${base64restart} | base64 -d > /usr/local/bin/restart.sh\nchmod +x /usr/local/bin/restart.sh\n\necho ${base64config_blobStorage} | base64 -d > /usr/local/bin/config_blobStorage.sh\nchmod +x /usr/local/bin/config_blobStorage.sh\n\n# Install azure cli\nAZURE_CLI_VERSION=2.90.0\napt-get install -y apt-transport-https ca-certificates gnupg lsb-release\ncurl -sLS https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /etc/apt/trusted.gpg.d/microsoft.gpg\necho \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main\" | tee /etc/apt/sources.list.d/azure-cli.list\napt-get update\napt-get install -y azure-cli=${AZURE_CLI_VERSION}-1~$(lsb_release -cs)\n\naz login --identity --client-id ${masterIdentityClientId} --allow-no-subscriptions\n\necho \"DPkg::Lock::Timeout \\\"-1\\\";\" > /etc/apt/apt.conf.d/99timeout\n\nexport HOME=\"/root\"\n\n# Install OpenVidu\n/usr/local/bin/install.sh || { echo \"[OpenVidu] error installing OpenVidu\"; exit 1; }\n\n#Config blob storage\n/usr/local/bin/config_blobStorage.sh || { echo \"[OpenVidu] error configuring Blob Storage\"; exit 1; }\n\n# Start OpenVidu\nsystemctl start openvidu || { echo \"[OpenVidu] error starting OpenVidu\"; exit 1; }\n\n# Update shared secret\n/usr/local/bin/after_install.sh || { echo \"[OpenVidu] error updating shared secret\"; exit 1; }\n\n# Launch on reboot\necho \"@reboot /usr/local/bin/restart.sh >> /var/log/openvidu-restart.log\" 2>&1 | crontab\n\n# check_app_ready.sh internally caps its wait at 1200s\n/usr/local/bin/check_app_ready.sh || { echo \"[OpenVidu] master node did not become healthy\"; exit 1; }\n\naz keyvault secret set --vault-name ${keyVaultName} --name FINISH-MASTER-NODE --value \"true\"\n\nMASTER_NODE_NUM=${masterNodeNum}\nif [[ $MASTER_NODE_NUM -eq 4 ]]; then\n # Creating scale in lock\n set +e\n az storage blob upload --account-name ${storageAccountName} --container-name automation-locks --name lock.txt --file /dev/null --auth-mode key\n set -e\nfi\n", - "installScriptTemplateMedia": "#!/bin/bash -x\nDOMAIN=\n\n# Install dependencies\necho \"DPkg::Lock::Timeout \\\"-1\\\";\" > /etc/apt/apt.conf.d/99timeout\n\napt-get update && apt-get install -y \\\n curl \\\n unzip \\\n jq \\\n wget\n\n# Get own private IP\nPRIVATE_IP=$(curl -H Metadata:true --noproxy \"*\" \"http://169.254.169.254/metadata/instance/network/interface/0/ipv4/ipAddress/0/privateIpAddress?api-version=2017-08-01&format=text\")\n\n# Gate 1: wait for master secrets and IPs before installing\nWAIT_INTERVAL=5\nMAX_RETRIES=360\nRETRIES=0\nset +e\nwhile true; do\n ALL_SECRETS_GENERATED=$(az keyvault secret show --vault-name ${keyVaultName} --name ALL-SECRETS-GENERATED --query value -o tsv 2>/dev/null)\n MASTER_NODE_1_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-1-PRIVATE-IP --query value -o tsv 2>/dev/null)\n MASTER_NODE_2_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-2-PRIVATE-IP --query value -o tsv 2>/dev/null)\n MASTER_NODE_3_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-3-PRIVATE-IP --query value -o tsv 2>/dev/null)\n MASTER_NODE_4_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-4-PRIVATE-IP --query value -o tsv 2>/dev/null)\n\n if [ \"$ALL_SECRETS_GENERATED\" == \"true\" ] &&\n [ \"$MASTER_NODE_1_PRIVATE_IP\" != \"\" ] &&\n [ \"$MASTER_NODE_2_PRIVATE_IP\" != \"\" ] &&\n [ \"$MASTER_NODE_3_PRIVATE_IP\" != \"\" ] &&\n [ \"$MASTER_NODE_4_PRIVATE_IP\" != \"\" ]; then\n break\n fi\n\n RETRIES=$((RETRIES + 1))\n if [ $RETRIES -ge $MAX_RETRIES ]; then\n echo \"[OpenVidu] timed out after 30 min waiting for master nodes to generate secrets and publish their IPs\"\n exit 1\n fi\n\n sleep $WAIT_INTERVAL\ndone\nset -e\n\nMASTER_NODE_1_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-1-PRIVATE-IP --query value -o tsv)\nMASTER_NODE_2_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-2-PRIVATE-IP --query value -o tsv)\nMASTER_NODE_3_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-3-PRIVATE-IP --query value -o tsv)\nMASTER_NODE_4_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-4-PRIVATE-IP --query value -o tsv)\nMASTER_NODE_PRIVATE_IP_LIST=\"$MASTER_NODE_1_PRIVATE_IP,$MASTER_NODE_2_PRIVATE_IP,$MASTER_NODE_3_PRIVATE_IP,$MASTER_NODE_4_PRIVATE_IP\"\nREDIS_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name REDIS-PASSWORD --query value -o tsv)\nENABLED_MODULES=$(az keyvault secret show --vault-name ${keyVaultName} --name ENABLED-MODULES --query value -o tsv)\nOPENVIDU_VERSION=$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-VERSION --query value -o tsv)\n\n# Download first: sh <(curl ...) would silently run an empty script on a transient curl failure\nINSTALLER_SCRIPT=\"/tmp/install_ov_media_node.sh\"\ncurl -fsSL --retry 8 --retry-all-errors --retry-delay 5 -o \"$INSTALLER_SCRIPT\" \"https://get.openvidu.io/pro/ha/$OPENVIDU_VERSION/install_ov_media_node.sh\"\nif [ ! -s \"$INSTALLER_SCRIPT\" ]; then\n echo \"[OpenVidu] failed to download the media node installer script\"\n exit 1\nfi\n\n# Base command\nINSTALL_COMMAND=\"sh $INSTALLER_SCRIPT\"\n\n# Common arguments\nCOMMON_ARGS=(\n\"--no-tty\"\n\"--install\"\n\"--environment=azure\"\n\"--deployment-type='ha'\"\n\"--node-role='media-node'\"\n\"--master-node-private-ip-list=$MASTER_NODE_PRIVATE_IP_LIST\"\n\"--private-ip=$PRIVATE_IP\"\n\"--enabled-modules='$ENABLED_MODULES'\"\n\"--redis-password=$REDIS_PASSWORD\"\n)\n\n# Construct the final command with all arguments\nFINAL_COMMAND=\"$INSTALL_COMMAND $(printf \"%s \" \"${COMMON_ARGS[@]}\")\"\n\n# Install OpenVidu\nexec bash -c \"$FINAL_COMMAND\"\n", + "installScriptTemplateMedia": "#!/bin/bash -x\nDOMAIN=\n\n# Install dependencies\necho \"DPkg::Lock::Timeout \\\"-1\\\";\" > /etc/apt/apt.conf.d/99timeout\n\napt-get update && apt-get install -y \\\n curl \\\n unzip \\\n jq \\\n wget\n\n# Get own private IP\nPRIVATE_IP=$(curl -H Metadata:true --noproxy \"*\" \"http://169.254.169.254/metadata/instance/network/interface/0/ipv4/ipAddress/0/privateIpAddress?api-version=2017-08-01&format=text\")\n\n# Gate 1: wait for master secrets and IPs before installing\nWAIT_INTERVAL=5\nMAX_RETRIES=360\nRETRIES=0\nset +e\nwhile true; do\n ALL_SECRETS_GENERATED=$(az keyvault secret show --vault-name ${keyVaultName} --name ALL-SECRETS-GENERATED --query value -o tsv 2>/dev/null)\n MASTER_NODE_1_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-1-PRIVATE-IP --query value -o tsv 2>/dev/null)\n MASTER_NODE_2_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-2-PRIVATE-IP --query value -o tsv 2>/dev/null)\n MASTER_NODE_3_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-3-PRIVATE-IP --query value -o tsv 2>/dev/null)\n MASTER_NODE_4_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-4-PRIVATE-IP --query value -o tsv 2>/dev/null)\n\n if [ \"$ALL_SECRETS_GENERATED\" == \"true\" ] &&\n [ \"$MASTER_NODE_1_PRIVATE_IP\" != \"\" ] &&\n [ \"$MASTER_NODE_2_PRIVATE_IP\" != \"\" ] &&\n [ \"$MASTER_NODE_3_PRIVATE_IP\" != \"\" ] &&\n [ \"$MASTER_NODE_4_PRIVATE_IP\" != \"\" ]; then\n break\n fi\n\n RETRIES=$((RETRIES + 1))\n if [ $RETRIES -ge $MAX_RETRIES ]; then\n echo \"[OpenVidu] timed out after 30 min waiting for master nodes to generate secrets and publish their IPs\"\n exit 1\n fi\n\n sleep $WAIT_INTERVAL\ndone\nset -e\n\nMASTER_NODE_1_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-1-PRIVATE-IP --query value -o tsv)\nMASTER_NODE_2_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-2-PRIVATE-IP --query value -o tsv)\nMASTER_NODE_3_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-3-PRIVATE-IP --query value -o tsv)\nMASTER_NODE_4_PRIVATE_IP=$(az keyvault secret show --vault-name ${keyVaultName} --name MASTER-NODE-4-PRIVATE-IP --query value -o tsv)\nMASTER_NODE_PRIVATE_IP_LIST=\"$MASTER_NODE_1_PRIVATE_IP,$MASTER_NODE_2_PRIVATE_IP,$MASTER_NODE_3_PRIVATE_IP,$MASTER_NODE_4_PRIVATE_IP\"\nREDIS_PASSWORD=$(az keyvault secret show --vault-name ${keyVaultName} --name REDIS-PASSWORD --query value -o tsv)\nOPENVIDU_VERSION=$(az keyvault secret show --vault-name ${keyVaultName} --name OPENVIDU-VERSION --query value -o tsv)\n\n# Download first: sh <(curl ...) would silently run an empty script on a transient curl failure\nINSTALLER_SCRIPT=\"/tmp/install_ov_media_node.sh\"\ncurl -fsSL --retry 8 --retry-all-errors --retry-delay 5 -o \"$INSTALLER_SCRIPT\" \"https://get.openvidu.io/pro/ha/$OPENVIDU_VERSION/install_ov_media_node.sh\"\nif [ ! -s \"$INSTALLER_SCRIPT\" ]; then\n echo \"[OpenVidu] failed to download the media node installer script\"\n exit 1\nfi\n\n# Base command\nINSTALL_COMMAND=\"sh $INSTALLER_SCRIPT\"\n\n# Common arguments\nCOMMON_ARGS=(\n\"--no-tty\"\n\"--install\"\n\"--environment=azure\"\n\"--deployment-type='ha'\"\n\"--node-role='media-node'\"\n\"--master-node-private-ip-list=$MASTER_NODE_PRIVATE_IP_LIST\"\n\"--private-ip=$PRIVATE_IP\"\n\"--redis-password=$REDIS_PASSWORD\"\n)\n\n# Construct the final command with all arguments\nFINAL_COMMAND=\"$INSTALL_COMMAND $(printf \"%s \" \"${COMMON_ARGS[@]}\")\"\n\n# Install OpenVidu\nexec bash -c \"$FINAL_COMMAND\"\n", "stop_media_nodesScriptMediaTemplate": "#!/bin/bash\nset -e\n\n# Pause the health watchdog before draining so it never reimages a node that is being\n# drained for scale-in (synchronous; the drain runs outside the watchdog's cgroup).\ntouch /run/openvidu-media-health.paused\nsystemctl stop openvidu-media-health 2>/dev/null || true\n\nif ! (set -o noclobber ; echo > /tmp/global.lock) ; then\n exit 1 # the global.lock already exists\nfi\n\n# Execute if docker is installed\nif [ -x \"$(command -v docker)\" ]; then\n\n echo \"Stopping media node services and waiting for termination...\"\n docker container kill --signal=SIGQUIT openvidu 2>/dev/null || true\n docker container kill --signal=SIGQUIT ingress 2>/dev/null || true\n docker container kill --signal=SIGQUIT egress 2>/dev/null || true\n for agent_container in $(docker ps --filter \"label=openvidu-agent=true\" --format '{{.Names}}' 2>/dev/null); do\n docker container kill --signal=SIGQUIT \"$agent_container\" 2>/dev/null || true\n done\n\n # If this node is being replaced because it is unhealthy, do not wait for sessions to end.\n if [ -f /run/openvidu-unhealthy ]; then\n docker ps -q | xargs -r docker kill >/dev/null 2>&1 || true\n fi\n\n # Wait for running containers to not be openvidu, ingress or egress\n while [ \"$(docker ps --filter 'label=openvidu-agent=true' -q 2>/dev/null | wc -l)\" -gt 0 ] || \\\n [ \"$(docker inspect -f '{{.State.Running}}' openvidu 2>/dev/null)\" = \"true\" ] || \\\n [ \"$(docker inspect -f '{{.State.Running}}' ingress 2>/dev/null)\" = \"true\" ] || \\\n [ \"$(docker inspect -f '{{.State.Running}}' egress 2>/dev/null)\" = \"true\" ]; do\n echo \"Waiting for containers to stop...\"\n sleep 5\n done\nfi\n\naz login --identity --client-id ${mediaIdentityClientId}\n\nRESOURCE_GROUP_NAME=${resourceGroupName}\nVM_SCALE_SET_NAME=${vmScaleSetName}\nSUBSCRIPTION_ID=${subscriptionId}\nBEFORE_INSTANCE_ID=$(curl -H Metadata:true --noproxy \"*\" \"http://169.254.169.254/metadata/instance?api-version=2021-02-01\" | jq -r '.compute.resourceId')\nINSTANCE_ID=$(echo $BEFORE_INSTANCE_ID | awk -F'/' '{print $NF}')\nRESOURCE_ID=/subscriptions/$SUBSCRIPTION_ID/resourcegroups/$RESOURCE_GROUP_NAME/providers/Microsoft.Compute/virtualMachineScaleSets/$VM_SCALE_SET_NAME\n\nTIMESTAMP=$(date -u +\"%Y-%m-%dT%H:%M:%SZ\")\naz tag update --resource-id $RESOURCE_ID --operation replace --tags \"STATUS\"=\"HEALTHY\" \"InstanceDeleteTime\"=\"$TIMESTAMP\" \"storageAccount\"=\"${storageAccountName}\"\n\naz vmss delete-instances --resource-group $RESOURCE_GROUP_NAME --name $VM_SCALE_SET_NAME --instance-ids $INSTANCE_ID\n", "openviduMediaHealthScript": "#!/bin/bash\n# OpenVidu Media Node health watchdog.\n#\n# Asks the cloud to replace this Media Node with a new one, keeping the number of\n# Media Nodes, through /usr/local/bin/openvidu-media-replace.sh, when:\n# - its bootstrap failed (the user-data wrote the bootstrap-failed marker): after a\n# cool-down, so a persistent failure does not churn nodes and can be inspected,\n# - its bootstrap did not finish BOOTSTRAP_DEADLINE_SEC after boot,\n# - LiveKit fails its health check (HTTP 200 on PROBE_URL): for HARD_UNHEALTHY_AFTER_SEC\n# while it is down (connection refused or closed), or for SOFT_UNHEALTHY_AFTER_SEC\n# while it answers an error or times out. Soft failures are not counted while the CPU\n# is saturated (an overloaded LiveKit reports Not Ready), and no failure is counted in\n# the WARMUP_SEC after openvidu.service (re)started.\n# Nothing is replaced while no master answers a Redis PING (MASTER_ADDRS): a master outage\n# fails the health check of every Media Node at once, and a new node could not bootstrap\n# either; LiveKit failures are not counted until a master answers again. Once requested,\n# the replacement is requested again every REPLACE_RETRY_SEC until the node goes away.\n#\n# Settings: /etc/openvidu/media-health.env (sourced every cycle; MASTER_ADDRS=\"ip:port ...\")\n# Pause: touch /etc/openvidu/media-health.disabled (drain scripts use /run/openvidu-media-health.paused)\n# Logs: journalctl -u openvidu-media-health\n#\n# This file is embedded verbatim in CloudFormation !Sub blocks, Bicep strings and\n# Terraform heredocs, so it must never contain a dollar sign or a percent sign followed\n# by an opening brace, nor two opening braces in a row.\n\nSTATE_DIR=/var/lib/openvidu-media-health\nINSTALLED_MARKER=\"$STATE_DIR/installed\"\nBOOTSTRAP_FAILED_MARKER=\"$STATE_DIR/bootstrap-failed\"\nREPLACE_SCRIPT=/usr/local/bin/openvidu-media-replace.sh\nENV_FILE=/etc/openvidu/media-health.env\nPAUSE_FILE=/etc/openvidu/media-health.disabled\nDRAIN_PAUSE_FILE=/run/openvidu-media-health.paused\n\nlog() { echo \"[media-health] $*\"; }\n\n# Seconds since boot: monotonic, unaffected by clock steps\nuptime_sec() { cut -d. -f1 /proc/uptime; }\n\n# Busy CPU percentage since the previous call, in BUSY (0 on the first call)\ncpu_busy() {\n read -r _ c_user c_nice c_system c_idle c_iowait c_irq c_softirq c_steal _ < /proc/stat\n total=$((c_user + c_nice + c_system + c_idle + c_iowait + c_irq + c_softirq + c_steal))\n idle=$((c_idle + c_iowait))\n BUSY=0\n if [ -n \"$PREV_TOTAL\" ] && [ \"$total\" -gt \"$PREV_TOTAL\" ]; then\n BUSY=$((100 * (total - PREV_TOTAL - idle + PREV_IDLE) / (total - PREV_TOTAL)))\n fi\n PREV_TOTAL=$total\n PREV_IDLE=$idle\n}\n\n# openvidu.service is running and entered the active state less than WARMUP_SEC ago\n# (a stopped or failed openvidu.service is not starting: no warm-up for it)\nopenvidu_starting() {\n case \"$(systemctl show -p ActiveState --value openvidu 2>/dev/null)\" in\n active|activating|reloading) ;;\n *) return 1 ;;\n esac\n since=$(systemctl show -p ActiveEnterTimestampMonotonic --value openvidu 2>/dev/null)\n case \"$since\" in ''|0|*[!0-9]*) return 1 ;; esac\n [ $(($(uptime_sec) - since / 1000000)) -lt \"$WARMUP_SEC\" ]\n}\n\n# A master answers a Redis PING (+PONG, or -NOAUTH when a password is required). A bare\n# TCP connect would also succeed against a wedged Redis.\nmaster_serving() {\n [ -n \"$MASTER_ADDRS\" ] || return 1\n for addr in $MASTER_ADDRS; do\n host=$(echo \"$addr\" | cut -d: -f1)\n port=$(echo \"$addr\" | cut -d: -f2)\n reply=$(timeout 5 bash -c 'exec 3<>\"/dev/tcp/$0/$1\" && printf \"PING\\r\\n\" >&3 && head -c 7 <&3' \"$host\" \"$port\" 2>/dev/null)\n case \"$reply\" in\n +PONG*|-NOAUTH*) return 0 ;;\n esac\n done\n return 1\n}\n\n# Request the replacement of this node ($1 = reason). Gated on a master answering, except\n# in the bootstrap phase before the master addresses are known.\nrequest_replacement() {\n now=$(uptime_sec)\n if [ -n \"$REQUESTED_AT\" ] && [ $((now - REQUESTED_AT)) -lt \"$REPLACE_RETRY_SEC\" ]; then\n return\n fi\n if [ -n \"$MASTER_ADDRS\" ] || [ -f \"$INSTALLED_MARKER\" ]; then\n if ! master_serving; then\n if [ -z \"$HOLD_LOGGED_AT\" ] || [ $((now - HOLD_LOGGED_AT)) -ge 600 ]; then\n log \"$1, but no master answers a Redis PING (MASTER_ADDRS='$MASTER_ADDRS'): not replacing this node\"\n HOLD_LOGGED_AT=$now\n fi\n return\n fi\n fi\n log \"$1: requesting the replacement of this node\"\n if \"$REPLACE_SCRIPT\" \"$1\"; then\n REQUESTED_AT=$now\n log \"replacement requested\"\n else\n log \"the replacement request failed, retrying in $INTERVAL_SEC s\"\n fi\n}\n\nmkdir -p \"$STATE_DIR\"\nREQUESTED_AT=\"\"\nHOLD_LOGGED_AT=\"\"\nFAILED_SEEN_AT=\"\"\nFAIL_SINCE=\"\"\nSATURATED=\"\"\nPREV_TOTAL=\"\"\nPREV_IDLE=\"\"\nlog \"started\"\n\nwhile true; do\n PROBE_URL=http://127.0.0.1:7880/\n INTERVAL_SEC=30\n HARD_UNHEALTHY_AFTER_SEC=300\n SOFT_UNHEALTHY_AFTER_SEC=600\n CPU_SATURATED_PCT=90\n WARMUP_SEC=900\n BOOTSTRAP_DEADLINE_SEC=5400\n BOOTSTRAP_FAILURE_COOLDOWN_SEC=600\n REPLACE_RETRY_SEC=600\n MASTER_ADDRS=\"\"\n [ -f \"$ENV_FILE\" ] && . \"$ENV_FILE\"\n NOW=$(uptime_sec)\n cpu_busy\n\n if [ -f \"$PAUSE_FILE\" ] || [ -f \"$DRAIN_PAUSE_FILE\" ]; then\n FAIL_SINCE=\"\"\n elif [ -f \"$BOOTSTRAP_FAILED_MARKER\" ]; then\n if [ -z \"$FAILED_SEEN_AT\" ]; then\n FAILED_SEEN_AT=$NOW\n log \"bootstrap failed ($(head -c 300 \"$BOOTSTRAP_FAILED_MARKER\")): replacing this node in $BOOTSTRAP_FAILURE_COOLDOWN_SEC s\"\n fi\n if [ $((NOW - FAILED_SEEN_AT)) -ge \"$BOOTSTRAP_FAILURE_COOLDOWN_SEC\" ]; then\n request_replacement \"bootstrap failed: $(head -c 300 \"$BOOTSTRAP_FAILED_MARKER\")\"\n fi\n elif [ ! -f \"$INSTALLED_MARKER\" ]; then\n if [ \"$NOW\" -ge \"$BOOTSTRAP_DEADLINE_SEC\" ]; then\n request_replacement \"bootstrap not finished $BOOTSTRAP_DEADLINE_SEC s after boot\"\n fi\n elif curl -sf -o /dev/null --connect-timeout 3 --max-time 15 \"$PROBE_URL\"; then\n [ -n \"$FAIL_SINCE\" ] && log \"LiveKit healthy again after $((NOW - FAIL_SINCE)) s\"\n FAIL_SINCE=\"\"\n SATURATED=\"\"\n else\n RC=$?\n case \"$RC\" in\n 7|52|56) KIND=hard ;;\n *) KIND=soft ;;\n esac\n if openvidu_starting; then\n FAIL_SINCE=\"\"\n elif ! master_serving; then\n # A master outage fails the health check of every Media Node at once: not counted,\n # so LiveKit gets the whole window to reconnect once a master answers again\n FAIL_SINCE=\"\"\n if [ -z \"$HOLD_LOGGED_AT\" ] || [ $((NOW - HOLD_LOGGED_AT)) -ge 600 ]; then\n log \"LiveKit health check failed (curl exit $RC), but no master answers a Redis PING (MASTER_ADDRS='$MASTER_ADDRS'): not counted\"\n HOLD_LOGGED_AT=$NOW\n fi\n elif [ \"$KIND\" = soft ] && [ \"$BUSY\" -ge \"$CPU_SATURATED_PCT\" ]; then\n [ -n \"$SATURATED\" ] || log \"LiveKit not ready (curl exit $RC) with the CPU $BUSY% busy: not counted\"\n SATURATED=1\n FAIL_SINCE=\"\"\n else\n SATURATED=\"\"\n if [ -z \"$FAIL_SINCE\" ]; then\n FAIL_SINCE=$NOW\n log \"LiveKit health check failed (curl exit $RC)\"\n fi\n LIMIT=$SOFT_UNHEALTHY_AFTER_SEC\n [ \"$KIND\" = hard ] && LIMIT=$HARD_UNHEALTHY_AFTER_SEC\n if [ $((NOW - FAIL_SINCE)) -ge \"$LIMIT\" ]; then\n request_replacement \"LiveKit unhealthy for $((NOW - FAIL_SINCE)) s (curl exit $RC)\"\n fi\n fi\n fi\n sleep \"$INTERVAL_SEC\"\ndone\n", "openviduMediaHealthUnit": "[Unit]\nDescription=OpenVidu Media Node health watchdog\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nExecStart=/usr/local/bin/openvidu-media-health.sh\nRestart=always\nRestartSec=30\n\n[Install]\nWantedBy=multi-user.target\n", diff --git a/openvidu-deployment/pro/ha/gcp/tf-gpc-openvidu-ha.tf b/openvidu-deployment/pro/ha/gcp/tf-gpc-openvidu-ha.tf index c0ae7a2aa..a2be260ed 100644 --- a/openvidu-deployment/pro/ha/gcp/tf-gpc-openvidu-ha.tf +++ b/openvidu-deployment/pro/ha/gcp/tf-gpc-openvidu-ha.tf @@ -324,11 +324,15 @@ resource "google_compute_instance_group" "master_node_group" { } locals { - is_arm_instance = startswith(var.masterNodesInstanceType, "c4a-") || startswith(var.masterNodesInstanceType, "t2a-") || startswith(var.masterNodesInstanceType, "n4a-") || startswith(var.masterNodesInstanceType, "a4x-") + # masterNodesInstanceType is deprecated in favor of masterNodeInstanceType; a non-empty + # deprecated value still takes precedence for backward compatibility. + master_node_instance_type = var.masterNodesInstanceType != "" ? var.masterNodesInstanceType : var.masterNodeInstanceType + + is_arm_instance = startswith(local.master_node_instance_type, "c4a-") || startswith(local.master_node_instance_type, "t2a-") || startswith(local.master_node_instance_type, "n4a-") || startswith(local.master_node_instance_type, "a4x-") yq_arch = local.is_arm_instance ? "arm64" : "amd64" - ubuntu_image = local.is_arm_instance ? "ubuntu-os-cloud/ubuntu-2404-noble-arm64-v20241219" : "ubuntu-os-cloud/ubuntu-2404-noble-amd64-v20241219" - is_c4a_instance = startswith(var.masterNodesInstanceType, "c4a-") + ubuntu_image = local.is_arm_instance ? "ubuntu-os-cloud/ubuntu-2404-lts-arm64" : "ubuntu-os-cloud/ubuntu-2404-lts-amd64" + is_c4a_instance = startswith(local.master_node_instance_type, "c4a-") } # Must match the subnetwork the master instances implicitly use (network = "default", no explicit subnetwork) @@ -357,7 +361,7 @@ locals { # Master Node 1 resource "google_compute_instance" "openvidu_master_node_1" { name = lower("${var.stackName}-master-node-1") - machine_type = var.masterNodesInstanceType + machine_type = local.master_node_instance_type zone = var.zone tags = [lower("${var.stackName}-master-node")] @@ -369,6 +373,14 @@ resource "google_compute_instance" "openvidu_master_node_1" { } } + # Keep existing Master Nodes when a newer Ubuntu 24.04 image is published, so a re-apply + # never recreates a running Master Node. The boot disk size stays managed by masterNodesDiskSize. + lifecycle { + ignore_changes = [ + boot_disk[0].initialize_params[0].image, + ] + } + network_interface { network = "default" network_ip = google_compute_address.master_internal_ip[0].address @@ -409,7 +421,7 @@ resource "google_compute_instance" "openvidu_master_node_1" { # Master Node 2 resource "google_compute_instance" "openvidu_master_node_2" { name = lower("${var.stackName}-master-node-2") - machine_type = var.masterNodesInstanceType + machine_type = local.master_node_instance_type zone = var.zone tags = [lower("${var.stackName}-master-node")] @@ -421,6 +433,14 @@ resource "google_compute_instance" "openvidu_master_node_2" { } } + # Keep existing Master Nodes when a newer Ubuntu 24.04 image is published, so a re-apply + # never recreates a running Master Node. The boot disk size stays managed by masterNodesDiskSize. + lifecycle { + ignore_changes = [ + boot_disk[0].initialize_params[0].image, + ] + } + network_interface { network = "default" network_ip = google_compute_address.master_internal_ip[1].address @@ -461,7 +481,7 @@ resource "google_compute_instance" "openvidu_master_node_2" { # Master Node 3 resource "google_compute_instance" "openvidu_master_node_3" { name = lower("${var.stackName}-master-node-3") - machine_type = var.masterNodesInstanceType + machine_type = local.master_node_instance_type zone = var.zone tags = [lower("${var.stackName}-master-node")] @@ -473,6 +493,14 @@ resource "google_compute_instance" "openvidu_master_node_3" { } } + # Keep existing Master Nodes when a newer Ubuntu 24.04 image is published, so a re-apply + # never recreates a running Master Node. The boot disk size stays managed by masterNodesDiskSize. + lifecycle { + ignore_changes = [ + boot_disk[0].initialize_params[0].image, + ] + } + network_interface { network = "default" network_ip = google_compute_address.master_internal_ip[2].address @@ -513,7 +541,7 @@ resource "google_compute_instance" "openvidu_master_node_3" { # Master Node 4 resource "google_compute_instance" "openvidu_master_node_4" { name = lower("${var.stackName}-master-node-4") - machine_type = var.masterNodesInstanceType + machine_type = local.master_node_instance_type zone = var.zone tags = [lower("${var.stackName}-master-node")] @@ -525,6 +553,14 @@ resource "google_compute_instance" "openvidu_master_node_4" { } } + # Keep existing Master Nodes when a newer Ubuntu 24.04 image is published, so a re-apply + # never recreates a running Master Node. The boot disk size stays managed by masterNodesDiskSize. + lifecycle { + ignore_changes = [ + boot_disk[0].initialize_params[0].image, + ] + } + network_interface { network = "default" network_ip = google_compute_address.master_internal_ip[3].address @@ -1017,7 +1053,7 @@ resource "google_cloud_scheduler_job" "scale_scheduler" { locals { is_arm_media_instance = startswith(var.mediaNodeInstanceType, "c4a-") || startswith(var.mediaNodeInstanceType, "t2a-") || startswith(var.mediaNodeInstanceType, "n4a-") || startswith(var.mediaNodeInstanceType, "a4x-") - media_ubuntu_image = local.is_arm_media_instance ? "ubuntu-os-cloud/ubuntu-2404-noble-arm64-v20241219" : "ubuntu-os-cloud/ubuntu-2404-noble-amd64-v20241219" + media_ubuntu_image = local.is_arm_media_instance ? "ubuntu-os-cloud/ubuntu-2404-lts-arm64" : "ubuntu-os-cloud/ubuntu-2404-lts-amd64" is_c4a_instance_media = startswith(var.mediaNodeInstanceType, "c4a-") } diff --git a/openvidu-deployment/pro/ha/gcp/variables.tf b/openvidu-deployment/pro/ha/gcp/variables.tf index b0283e883..9054dfa9d 100644 --- a/openvidu-deployment/pro/ha/gcp/variables.tf +++ b/openvidu-deployment/pro/ha/gcp/variables.tf @@ -85,16 +85,22 @@ variable "initialMeetApiKey" { } } -variable "masterNodesInstanceType" { +variable "masterNodeInstanceType" { description = "Specifies the GCE machine type for your OpenVidu Master Node" type = string default = "e2-standard-4" } +variable "masterNodesInstanceType" { + description = "Deprecated: replaced by masterNodeInstanceType. Kept for backward compatibility; if set to a non-empty value it still takes precedence over masterNodeInstanceType." + type = string + default = "" +} + variable "masterNodesDiskSize" { description = "Size of the disk in GB for master nodes" type = number - default = 100 + default = 200 validation { condition = var.masterNodesDiskSize >= 70 error_message = "masterNodesDiskSize must be at least 70 GB." diff --git a/openvidu-deployment/pro/singlenode/azure/cf-openvidu-singlenode.bicep b/openvidu-deployment/pro/singlenode/azure/cf-openvidu-singlenode.bicep index 246ec05cc..6facb61f6 100644 --- a/openvidu-deployment/pro/singlenode/azure/cf-openvidu-singlenode.bicep +++ b/openvidu-deployment/pro/singlenode/azure/cf-openvidu-singlenode.bicep @@ -768,7 +768,7 @@ resource openviduServer 'Microsoft.Compute/virtualMachines@2023-09-01' = { managedDisk: { storageAccountType: openviduVMSettings.osDiskType } - diskSizeGB: 100 + diskSizeGB: 200 } imageReference: openviduVMSettings.ubuntuOSVersion } @@ -975,19 +975,6 @@ resource webServerSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-11 direction: 'Inbound' } } - { - name: 'MinIO' - properties: { - protocol: 'Tcp' - sourceAddressPrefix: '*' - sourcePortRange: '*' - destinationAddressPrefix: '*' - destinationPortRange: '9000' - access: 'Allow' - priority: 170 - direction: 'Inbound' - } - } { name: 'WebRTC_traffic_UDP' properties: { diff --git a/openvidu-deployment/pro/singlenode/azure/cf-openvidu-singlenode.json b/openvidu-deployment/pro/singlenode/azure/cf-openvidu-singlenode.json index 1f1e915e6..467c906df 100644 --- a/openvidu-deployment/pro/singlenode/azure/cf-openvidu-singlenode.json +++ b/openvidu-deployment/pro/singlenode/azure/cf-openvidu-singlenode.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.46.1.21595", - "templateHash": "18422024254131943403" + "templateHash": "17066739396447275453" } }, "parameters": { @@ -280,7 +280,7 @@ "managedDisk": { "storageAccountType": "[variables('openviduVMSettings').osDiskType]" }, - "diskSizeGB": 100 + "diskSizeGB": 200 }, "imageReference": "[variables('openviduVMSettings').ubuntuOSVersion]" }, @@ -490,19 +490,6 @@ "direction": "Inbound" } }, - { - "name": "MinIO", - "properties": { - "protocol": "Tcp", - "sourceAddressPrefix": "*", - "sourcePortRange": "*", - "destinationAddressPrefix": "*", - "destinationPortRange": "9000", - "access": "Allow", - "priority": 170, - "direction": "Inbound" - } - }, { "name": "WebRTC_traffic_UDP", "properties": { diff --git a/openvidu-deployment/pro/singlenode/gcp/tf-gpc-openvidu-singlenode.tf b/openvidu-deployment/pro/singlenode/gcp/tf-gpc-openvidu-singlenode.tf index 3e3bcfc24..c55cfbca5 100644 --- a/openvidu-deployment/pro/singlenode/gcp/tf-gpc-openvidu-singlenode.tf +++ b/openvidu-deployment/pro/singlenode/gcp/tf-gpc-openvidu-singlenode.tf @@ -84,9 +84,14 @@ resource "google_compute_address" "public_ip_address" { region = var.region } +# rtcEngine replaced RTCEngine; the deprecated name still wins when it is set. +locals { + rtc_engine = var.RTCEngine != "" ? var.RTCEngine : var.rtcEngine +} + #Check if ARM locals { - ubuntu_image = local.is_arm_instance ? "ubuntu-os-cloud/ubuntu-2404-noble-arm64-v20241219" : "ubuntu-os-cloud/ubuntu-2404-noble-amd64-v20241219" + ubuntu_image = local.is_arm_instance ? "ubuntu-os-cloud/ubuntu-2404-lts-arm64" : "ubuntu-os-cloud/ubuntu-2404-lts-amd64" } # Compute instance for OpenVidu @@ -100,11 +105,17 @@ resource "google_compute_instance" "openvidu_server" { boot_disk { initialize_params { image = local.ubuntu_image - size = 100 + size = 200 type = "pd-standard" } } + # The image family moves to each new Ubuntu 24.04 build and the disk size can change between + # releases: both apply to new deployments only, so a re-apply never recreates this VM. + lifecycle { + ignore_changes = [boot_disk[0].initialize_params[0].image, boot_disk[0].initialize_params[0].size] + } + network_interface { network = "default" access_config { @@ -197,7 +208,7 @@ if [[ "${var.initialMeetApiKey}" != '' ]]; then fi OPENVIDU_PRO_LICENSE="$(/usr/local/bin/store_secret.sh save OPENVIDU_PRO_LICENSE ${var.openviduLicense})" -OPENVIDU_RTC_ENGINE="$(/usr/local/bin/store_secret.sh save OPENVIDU_RTC_ENGINE ${var.RTCEngine})" +OPENVIDU_RTC_ENGINE="$(/usr/local/bin/store_secret.sh save OPENVIDU_RTC_ENGINE ${local.rtc_engine})" # Store usernames and generate random passwords REDIS_PASSWORD="$(/usr/local/bin/store_secret.sh generate REDIS_PASSWORD)" diff --git a/openvidu-deployment/pro/singlenode/gcp/variables.tf b/openvidu-deployment/pro/singlenode/gcp/variables.tf index 74c97e753..295f5979c 100644 --- a/openvidu-deployment/pro/singlenode/gcp/variables.tf +++ b/openvidu-deployment/pro/singlenode/gcp/variables.tf @@ -103,13 +103,23 @@ variable "openviduLicense" { sensitive = true } -variable "RTCEngine" { +variable "rtcEngine" { description = "RTCEngine media engine to use. Allowed values are 'pion' and 'mediasoup'." type = string default = "mediasoup" validation { - condition = contains(["pion", "mediasoup"], var.RTCEngine) - error_message = "RTCEngine must be one of: pion, mediasoup" + condition = contains(["pion", "mediasoup"], var.rtcEngine) + error_message = "rtcEngine must be one of: pion, mediasoup" + } +} + +variable "RTCEngine" { + description = "Deprecated: use rtcEngine, the name every other Terraform template uses. Still honored: a non-empty value takes precedence over rtcEngine. It will be removed in a future release." + type = string + default = "" + validation { + condition = contains(["", "pion", "mediasoup"], var.RTCEngine) + error_message = "RTCEngine must be empty or one of: pion, mediasoup" } }