GCP Setup Guide¶
The following demonstrates how to deploy Puddle on GCP. The process involves steps that need to be
taken via the GCP console/gcloud command, as well as steps that will be taken on the Puddle Linux
VM. As such, please make sure you have permissions to do the following:
- Activate APIs
- Allocate a (preferably static) external IP address
- (Optional) Create a network/subnetwork and edit routes and firewall rules
- Configure firewall rules
- Configure VPC peering for private services access
- (Optional) Create service accounts and change project IAM policies
- (Optional) Create KMS key rings and keys
- Create a Cloud SQL for Postgres instance
- Create a Cloud Memorystore for Redis instance
- Create a VM
After the above has been verified, you are now ready to proceed.
GCP Resources¶
The first step is to set up GCP resources. All of these operations require a GCP project and an
initialized gcloud installation (see official documentation):
PROJECT=<your project **id**>
PROJECT_NUMBER=<your project **number**>
gcloud auth login
gcloud config set core/project $PROJECT
The puddle deployment runs in a single GCE zone/region:
ZONE=<deployment zone>
REGION=<deployment region>
To simplify the deployment, let’s also standardize the naming:
DEPLOYMENT=<name of the deployment>
Project Setup¶
First you need to make sure that the required APIs are enabled on the project by running:
gcloud services enable compute.googleapis.com
gcloud services enable servicenetworking.googleapis.com
gcloud services enable sql-component.googleapis.com
gcloud services enable redis.googleapis.com
Also make sure that you have enabled billing on the project.
Let’s also initialize the default configuration options:
NETWORK=default # default GCE network
SUBNET=default
BACKEND_SA="" # will use default GCE service account
PACKER_SA="" # will use default GCE service account
SYSTEM_SA="" # will use default GCE service account
Allocate Public IP¶
You will need to allocate a public IP for the Puddle backend VM.
gcloud compute addresses create "${DEPLOYMENT}-ip" --region=$REGION
(Optional) Custom VPC Network Setup¶
If you don’t want to use the default GCP network/subnet, you can create your own by running:
NETWORK="${DEPLOYMENT}-network"
SUBNET="${DEPLOYMENT}-subnet"
gcloud compute networks create $NETWORK --subnet-mode=custom
gcloud compute networks subnets create $SUBNET \
--network=$NETWORK \
--range=10.128.0.0/20 \
--enable-private-ip-google-access \
--region=$REGION
If you intend to disable public IPs for the Puddle-managed VMs, you have to configure Cloud NAT so that the VMs can access the Internet:
gcloud compute routers create "${DEPLOYMENT}-nat-router" \
--network $NETWORK \
--region $REGION
gcloud compute routers nats create "${DEPLOYMENT}-nat-config" \
--router-region $REGION \
--router "${DEPLOYMENT}-nat-router" \
--nat-all-subnet-ip-ranges \
--auto-allocate-nat-external-ips
Note that technically the Puddle backend VM can be in a different network/subnet than the rest of Puddle-provisioned VMs (image builds and systems). However, appropriate routing and firewall rules between the networks need to be ensured.
Firewall Setup¶
Puddle requires a few firewall rules to function correctly:
- TCP port
22(SSH access) for all VMs; this is required for Puddle to function (already allowed by thedefaultnetwork). - TCP ports
80/443(HTTP/HTTPs) for the Puddle backend VM (already allowed by thedefaultnetwork). - TCP ports
54321,12345, and8888(H2O-3, Driverless AI, and Jupyter, respectively) for all system VMs.
If you’re using a custom network, run:
gcloud compute firewall-rules create "${DEPLOYMENT}-allow-icmp" \
--network=$NETWORK --allow icmp
gcloud compute firewall-rules create "${DEPLOYMENT}-allow-ssh" \
--network=$NETWORK --allow tcp:22
gcloud compute firewall-rules create "${DEPLOYMENT}-allow-http" \
--network=$NETWORK --allow tcp:80 --target-tags=http-server
gcloud compute firewall-rules create "${DEPLOYMENT}-allow-https" \
--network=$NETWORK --allow tcp:443 --target-tags=https-server
For both default and custom networks, run:
gcloud compute firewall-rules create "${DEPLOYMENT}-allow-h2o" \
--network=$NETWORK --allow tcp:54321,tcp:12345,tcp:8888
VPC Peering setup¶
Next, set up private services access so that we can access our Cloud SQL and Cloud Memorystore instances via private IP addresses. (See Cloud SQL private IP documentation.)
If you don’t want to use private services access, you can skip this step.
gcloud beta compute addresses create "${DEPLOYMENT}-peering-range" \
--global \
--prefix-length=20 \
--description="Private services access connection" \
--network=$NETWORK \
--purpose=vpc_peering
gcloud services vpc-peerings connect \
--service=servicenetworking.googleapis.com \
--ranges="${DEPLOYMENT}-peering-range" \
--network=$NETWORK \
--project=$PROJECT
(Optional) Custom Service Account Setup¶
Puddle can run perfectly fine under the GCE default service account. (This is the default configuration.)
However, it might be better to create a designated service account for the Puddle backend VM as well as a designated service account for the VMs launched by Puddle (image builds and systems). To create the two accounts, run:
gcloud iam service-accounts create "${DEPLOYMENT}-backend" \
--display-name="Puddle Backend Service Account"
gcloud iam service-accounts create "${DEPLOYMENT}-packer" \
--display-name="Puddle Packer Service Account"
gcloud iam service-accounts create "${DEPLOYMENT}-system" \
--display-name="Puddle Systems Service Account"
BACKEND_SA="${DEPLOYMENT}-backend@${PROJECT}.iam.gserviceaccount.com"
PACKER_SA="${DEPLOYMENT}-packer@${PROJECT}.iam.gserviceaccount.com"
SYSTEM_SA="${DEPLOYMENT}-system@${PROJECT}.iam.gserviceaccount.com"
After that, you need to grant the backend service account required IAM permissions. First, allow Puddle backend to use the packer/system service accounts for new VMs:
gcloud iam service-accounts add-iam-policy-binding "${PACKER_SA}" \
--member="serviceAccount:${BACKEND_SA}" \
--role=roles/iam.serviceAccountUser
gcloud iam service-accounts add-iam-policy-binding "${SYSTEM_SA}" \
--member="serviceAccount:${BACKEND_SA}" \
--role=roles/iam.serviceAccountUser
Then allow Puddle backend to control the relevant GCP resources. By default, the Puddle Backend requires the following project permissions:
PERMISSIONS="
compute.disks.create
compute.disks.createSnapshot
compute.disks.delete
compute.disks.get
compute.disks.setLabels
compute.disks.use
compute.disks.useReadOnly
compute.globalOperations.get
compute.images.create
compute.images.delete
compute.images.get
compute.images.setLabels
compute.images.useReadOnly
compute.instances.create
compute.instances.delete
compute.instances.get
compute.instances.setLabels
compute.instances.setMachineResources
compute.instances.setMachineType
compute.instances.setMetadata
compute.instances.setScheduling
compute.instances.setServiceAccount
compute.instances.start
compute.instances.stop
compute.machineTypes.get
compute.snapshots.create
compute.snapshots.delete
compute.snapshots.get
compute.snapshots.setLabels
compute.snapshots.useReadOnly
compute.subnetworks.use
compute.subnetworks.useExternalIp
compute.zoneOperations.get
compute.zones.get
"
gcloud iam roles create puddleBackend \
--project=$PROJECT \
--title="Puddle backend" \
--description="Contains permissions required for Puddle backend to function." \
--stage=GA \
--permissions=$(echo $PERMISSIONS | tr " " ",")
gcloud projects add-iam-policy-binding $PROJECT \
--member="serviceAccount:${BACKEND_SA}" \
--role=projects/${PROJECT}/roles/puddleBackend
Note that you could also use the pre-defined role roles/compute.instanceAdmin.v1;
however, it grants many unnecessary permissions.
If you plan on using custom Packer startup scripts,
give $PACKER_SA the required permissions:
gcloud iam service-accounts add-iam-policy-binding "${PACKER_SA}" \
--member="serviceAccount:${PACKER_SA}" \
--role=roles/iam.serviceAccountUser
gcloud iam roles create packerStartupScriptRunner \
--project=$PROJECT \
--title="Packer startup script runner" \
--description="Allows running custom startup script in Packer VMs." \
--stage=GA \
--permissions=compute.instances.get,compute.instances.setMetadata,compute.zoneOperations.get
gcloud beta projects add-iam-policy-binding $PROJECT \
--member="serviceAccount:${PACKER_SA}" \
--role="projects/${PROJECT}/roles/packerStartupScriptRunner" \
--condition=title="Only apply to Packer VMs",expression="resource.name.startsWith(\"projects/${PROJECT}/zones/${ZONE}/instances/packer-\")"
(Optional) KMS Setup¶
Optionally, you can opt to encrypt system volumes using KMS keys.
First, you need give GCE permission to use KMS keys when creating disks by assigning the Cloud KMS CryptoKey Encrypter/Decrypter role to the Compute Engine Service Agent. (See KMS how-to guide.)
KMS_PROJECT=$PROJECT
gcloud projects add-iam-policy-binding $KMS_PROJECT \
--member "serviceAccount:service-${PROJECT_NUMBER}@compute-system.iam.gserviceaccount.com" \
--role roles/cloudkms.cryptoKeyEncrypterDecrypter
If you intend to use KMS keys from another project, change KMS_PROJECT accordingly.
If you want to create a unique key for each Puddle system, you need a KMS key ring.
Important: KMS key rings and key versions CANNOT BE DELETED, so create them carefully. See KMS object lifetime documentation for details. To create one in the deployment project, run:
gcloud services enable cloudkms.googleapis.com
gcloud kms keyrings create "${DEPLOYMENT}-key-ring" --location $REGION
See KMS documentation on how to create key rings/keys for more details. Note that disks can be encrypted only by keys in the same region or in the global location.
Finally, allow Puddle to control the KMS resources:
PERMISSIONS="$PERMISSIONS
cloudkms.cryptoKeys.create
cloudkms.cryptoKeys.get
cloudkms.cryptoKeyVersions.destroy
cloudkms.cryptoKeyVersions.list
cloudkms.keyRings.get
"
gcloud iam roles update puddleBackend \
--project=$PROJECT \
--permissions=$(echo $PERMISSIONS | tr " " ",")
Note that you could also use the pre-defined role roles/cloudkms.admin.
Cloud SQL for Postgres Setup¶
Now proceed to creating the Postgres database that is required for this Puddle setup:
gcloud beta sql instances create "$DEPLOYMENT-postgres" \
--database-version=POSTGRES_10 \
--no-assign-ip \
--no-storage-auto-increase \
--availability-type=regional \
--network="projects/${PROJECT}/global/networks/${NETWORK}" \
--region=$REGION \
--storage-size=50 \
--cpu=2 \
--memory=4 \
--backup \
--backup-start-time=00:00
read -s -p "Enter password:" PASSWORD
gcloud sql users create puddle \
--instance="$DEPLOYMENT-postgres" --password="${PASSWORD}"
Take note of the PRIVATE_ADDRESS value. It’ll be required to start Puddle later.
Cloud Memorystore for Redis Setup¶
Next, create the Redis database that is required for this Puddle setup:
gcloud redis instances create "$DEPLOYMENT-redis" \
--region=$REGION \
--redis-version=redis_4_0 \
--tier=STANDARD \
--network="projects/${PROJECT}/global/networks/${NETWORK}" \
--connect-mode=private-service-access
gcloud redis instances describe "$DEPLOYMENT-redis" --region=$REGION
Take note of the host value. It’ll be required to start Puddle later.
Puddle Backend VM Setup¶
While the RDS and Redis instances are starting, create a new VM for the Puddle backend server. We will not go into detail when it comes to creating a VM in GCP. However, we recommend the following configuration for the Puddle backend VM:
- OS: Ubuntu
- Memory: 8GB
- Storage: 100 GB
Create the VM by running:
gcloud compute instances create "${DEPLOYMENT}-backend" \
--image-family ubuntu-1804-lts \
--image-project ubuntu-os-cloud \
--boot-disk-size=100GB \
--boot-disk-type=pd-ssd \
--machine-type=n1-standard-2 \
--address="${DEPLOYMENT}-ip" \
--network=$NETWORK \
--subnet=$SUBNET \
--zone=$ZONE \
--scopes=cloud-platform \
${BACKEND_SA:+--service-account="${BACKEND_SA}"} \
--tags=http-server,https-server
Remove the http-server and https-server tags if you don’t want to allow traffic on ports
80 and 443, respectively, while the VM is on the default network/firewall.
If you want to use a custom SSH key pair, add the following argument:
--metadata="ssh-keys=${SSH_USERNAME}:${SSH_PUBKEY}"
Review the GCP Resources¶
The newly created Resource group should now contain these items. (Some of them are created implicitly):
- GCE Virtual machine
- PD SSD Disk
- Public IP address
- Firewall rules for ICMP, SSH, HTTP(S), Jupyter, and H2O products
- Cloud SQL for PostgreSQL isntance
- Cloud Memorystore for Redis instance
- VPC network peering and IP address range for private services access
- (optional) Custom VPC network/subnetwork and Cloud Router/NAT
- (optional) 3 service accounts, 2 custom IAM roles, and related IAM policies
- (optional) KMS key ring
Puddle Application¶
For this part, we will configure the VM created above.
To SSH onto the VM using your gcloud credentials, run:
gcloud beta compute ssh --zone $ZONE "${DEPLOYMENT}-backend"
Install Ansible¶
Puddle requires ansible. Use the following to install ansible:
Ubuntu
sudo apt update
sudo apt upgrade
sudo apt-add-repository --yes --update ppa:ansible/ansible
sudo apt install -y wget unzip redis-tools postgresql-client ansible
wget https://s3.amazonaws.com/puddle-release.h2o.ai/1.5.0/x86_64-ubuntu18/puddle_1.5.0_amd64.deb
sudo apt install -y puddle_1.5.0_amd64.deb
RHEL
sudo bash
yum install epel-release
yum install ansible
yum install postgres10
yum install redis
Create the License File¶
- ssh into the Virtual Machine.
- Create a file
/opt/h2oai/puddle/license.sigcontaining the license. Different path might be used, but this is the default.
Configuring Puddle¶
Now we will need to fill in the config.yaml file, which is located at /etc/puddle/config.yaml. The config.yaml should contain the following:
redis:
connection:
protocol: tcp
address:
password:
tls: true
db:
connection:
drivername: postgres
host:
port: 5432
user:
dbname: puddle
sslmode: require
password:
tls:
certFile:
keyFile:
connection:
port: 8081
license:
file: /opt/h2oai/puddle/license.sig
ssh:
publicKey: /opt/h2oai/puddle/ssh/id_rsa.pub
privateKey: /opt/h2oai/puddle/ssh/id_rsa
auth:
token:
secret:
activeDirectory:
enabled: false
server:
port: 389
baseDN:
security: tls
objectGUIDAttr: objectGUID
displayNameAttr: displayName
administratorsGroup: Puddle-Administrators
usersGroup: Puddle-Users
implicitGrant: false
azureAD:
enabled: false
useAADLoginExtension: true
awsCognito:
enabled: false
userPoolId:
userPoolWebClientId:
domain:
redirectSignIn:
redirectSignOut:
adminsGroup: Puddle-Administrators
usersGroup: Puddle-Users
implicitGrant: false
ldap:
enabled: false
host:
port: 389
skipTLS: false
useSSL: true
insecureSkipVerify: false
serverName:
baseDN:
bindDN:
bindPassword:
bindAllowAnonymousLogin: false
authenticationFilter: "(uid=%s)"
authorizationFlow: userAttribute
authorizationFilter: "(memberOf=%s)"
authorizationSearchValueAttribute: dn
uidAttributeName: uid
uidNumberAttributeName: uidnumber
emailAttributeName: email
implicitGrant: false
adminsGroup: Puddle-Administrators
usersGroup: Puddle-Users
oidc:
enabled: false
issuer:
clientId:
clientSecret:
redirectUrl: /oicd/authorization-code/callback
scopes:
- openid
- profile
- email
implicitGrant: false
adminRole: Puddle-Administrators
userRole: Puddle-Users
packer:
path: /opt/h2oai/puddle/deps/packer
usePublicIP: true
buildTimeoutHours: 1
nvidiaDriversURL:
cudaURL:
cudnnURL:
cudnnDevURL:
terraformURL:
driverlessAIURLPrefix:
h2o3URLPrefix:
terraform:
path: /opt/h2oai/puddle/deps/terraform
usePublicIP: true
pluginDir: /opt/h2oai/puddle/deps/terraform_plugins/
reverseProxy:
enabled: true
port: 443
caCertificate: /opt/h2oai/puddle/certs/ca/cert.pem
caPrivateKey: /opt/h2oai/puddle/certs/ca/key.pem
clientCertificate: /opt/h2oai/puddle/certs/client/cert.pem
clientPrivateKey: /opt/h2oai/puddle/certs/client/key.pem
backend:
baseURL:
connections:
usePublicIP: true
webclient:
usePublicIP: true
userSshAccessEnabled: true
providers:
azure:
enabled: false
authority:
location:
rg:
vnetrg:
vnet:
sg:
subnet:
enterpriseApplicationObjectId:
adminRoleId:
publicIpEnabled: true
packerInstanceType:
sshUsername: puddle
sourceSharedImageGallery:
subscriptionId:
rg:
name:
imageName:
imageVersion:
sourceImageRG:
sourceImageName:
sourceImagePublisher: Canonical
sourceImageOffer: UbuntuServer
sourceImageSku: 16.04-LTS
imageTags:
customDataScriptPath:
packerCustomDataScriptPath:
storageDiskLun: 0
storageDiskFileSystem: ext4
storageDiskDevice: /dev/sdc
aws:
enabled: false
owner:
vpcId:
sgIds:
subnetId:
iamInstanceProfile:
publicIpEnabled: true
packerInstanceType:
encryptEBSVolume: true
ebsKMSKeyArn:
metadataEndpointIAMRole: http://169.254.169.254/latest/meta-data/iam/info
suppressIAMRoleCheck: false
sshUsername: ubuntu
sourceAMIOwner: '099720109477'
sourceAMINameFilter: ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*
packerRunTags:
amiTags:
userDataScriptPath:
packerUserDataScriptPath:
storageEBSDeviceName: /dev/sdf
storageDiskFileSystem: ext4
storageDiskDevice: /dev/nvme1n1
storageDiskDeviceGpu: /dev/xvdf
gcp:
enabled: false
project:
zone:
network: default
subnetwork: ""
publicIpEnabled: true
encryptVolume: true
volumeKmsKeyId: ""
volumeKmsKeyRingName:
volumeKmsKeyRingLocation:
serviceAccountEmail: ""
sshUsername: puddle
storageDiskFileSystem: ext4
startupScriptPath: ""
imageLabels:
packerServiceAccountEmail: ""
packerSourceImageProject: ubuntu-os-cloud
packerSourceImageFamily: ubuntu-1604-lts
packerInstanceType: n1-highmem-8
packerAcceleratorType: nvidia-tesla-v100
packerAcceleratorCount: 1
packerStartupScriptPath: ""
packerRunLabels:
products:
dai:
configTomlTemplatePath: "/opt/h2oai/puddle/configs/dai/config.toml"
license:
h2o3:
authEnabled: true
logs:
dir: /opt/h2oai/puddle/logs
maxSize: 1000
maxBackups: 15
maxAge: 60
compress: true
level: trace
mailing:
enabled: true
server:
username:
password:
fromAddress: puddle@h2o.ai
fromName: Puddle
recipients:
offsetHours: 24
- ssh into the Virtual machine.
- Fill in the fields in the config.yaml.
Values for
redis.connection.*can be found in following way:
- Microsoft Azure:
- Search for Azure Cache for Redis.
- Select the newly created Redis instance.
- Select Access keys.
- Amazon AWS:
- Go to ElastiCache Dashboard.
- Select Redis.
- Select the cluster used by Puddle.
- Select Description tab.
- Google GCP:
- Go to Memorystore > Redis
- Select the instance used by Puddle.
- See Connection properties
Values for
db.connection.*can be found in following way:
- Microsoft Azure:
- Search for Azure Database for PostgreSQL servers.
- Select the newly created PostgreSQL instance.
- Select Connection strings.
- Use the password that was provided when creating the PostgreSQL database.
- Amazon AWS:
- Go to Amazon RDS.
- Select Databases.
- Select the database used by Puddle.
- Google GCP:
- Go to SQL
- Select the instance used by Puddle.
- See Connect to this instance
tls.certFileshould point to the PEM encoded certificate file if you want to use HTTPS. If you don’t want to use HTTPS, leave this property empty. If you set this property, thentls.keyFilemust be set as well.
tls.keyFileshould point to the PEM encoded private key file if you want to use HTTPS. The private key must be not encrypted by password. If you don’t want to use HTTPS, leave this property empty. If you set this property, thentls.certFilemust be set as well.
connection.portshould be the port where Puddle backend should be running. Defaults to 80 or 443 based on TLS config.
license.fileshould be a path to the file containing the license (created in previous step).
ssh.publicKeyshould be the path to ssh public key (for example /opt/h2oai/puddle/ssh/id_rsa.pub), which will be used by Puddle to talk to the Systems. If this ssh key is changed, Puddle won’t be able to talk to the Systems created with old key, and these will have to be destroyed.
ssh.privateKeyshould be the path to ssh private key (for example /opt/h2oai/puddle/ssh/id_rsa), which will be used by Puddle to talk to the Systems. If this ssh key is changed, Puddle won’t be able to talk to the Systems created with old key, and these will have to be destroyed.
auth.token.secretshould be a random string. It is used to encrypt the tokens between the backend and frontend. For example the following could be used to generate the secret:tr -cd '[:alnum:]' < /dev/urandom | fold -w32 | head -n1
auth.activeDirectory.enabledshould be true/false and is false by default. If true then authentication using ActiveDirectory is enabled.
auth.activeDirectory.servershould be the hostname of the ActiveDirectory server, for example puddle-ad.h2o.ai.
auth.activeDirectory.portshould be the port where ActiveDirectory is accessible, defaults to 389.
auth.activeDirectory.baseDNshould be the BaseDN used for search.
auth.activeDirectory.securityshould be the security level used in communication with AD server. Could be none, start_tls, tls, defaults to tls.
auth.activeDirectory.objectGUIDAttrshould be the name of the attribute used as ID of the user, defaults to objectGUID.
auth.activeDirectory.displayNameAttrshould be the name of the attribute used to determine groups where user is member, defaults to memberOf.
auth.activeDirectory.administratorsGroupshould be the name of the Administrators group. Users in this group are assigned Administrator role in Puddle, users in Administrators group and Users group are considered Administrators.
auth.activeDirectory.usersGroupshould be the name of the Users group. Users in this group are assigned User role in Puddle, users in Administrators group and Users group are considered Administrators.
auth.activeDirectory.implicitGrantshould be true/false and is false by default. If true, then users are allowed access to Puddle (using user role) even if they are not members of Administrators nor Users group. If false, then users must be members of at least one group to be allowed access to Puddle.
auth.azureAD.enabledshould be true/false and is false by default. If true, then authentication using Azure Active Directory is enabled. Also, if true, you have to setprovider.azure.authority,provider.azure.enterpriseApplicationObjectId, andprovider.azure.adminRoleId(provider.azure.enabledcan be remain false); you also have to setAZURE_SUBSCRIPTION_ID,AZURE_TENANT_ID, andAZURE_CLIENT_ID(see below).
auth.azureAD.useAADLoginExtensionshould be true/false and is false by default. If true, then ssh access to provisioned Virtual machines will use the Azure AD for authentication. Check https://docs.microsoft.com/en-us/azure/virtual-machines/linux/login-using-aad for more information. Cannot be enabled, if using proxy for egress.
auth.awsCognito.enabledshould be true/false and is false by default. If true, then authentication using AWS Cognito is enabled.
auth.awsCognito.userPoolIdshould be the Pool Id, for example us-east-1_SlxxxxML1.
auth.awsCognito.userPoolWebClientIdshould be the App client id. The App client id can be found in following way:
- Go to the AWS Cognito User Pool used by Puddle.
- Select the App client settings.
- Use the value under ID.
auth.awsCognito.domainshould be the domain of the AWS Cognito User Pool, for example https://puddle.auth.<REGION>.amazoncognito.com. The domain can be found in following way:
- Go to the AWS Cognito User Pool used by Puddle.
- Select the Domain name.
auth.awsCognito.redirectSignInshould be https://<SERVER_ADDRESS>/aws-cognito-callback, please replace <SERVER_ADDRESS> with hostname where Puddle is running.
auth.awsCognito.redirectSignOutshould be https://<SERVER_ADDRESS>/logout, please replace <SERVER_ADDRESS> with hostname where Puddle is running.
auth.awsCognito.adminsGroupshould be the name of a group in AWS Cognito User Pool. If users are members of this group, they are assigned Administrator role in Puddle.
auth.awsCognito.usersGroupshould be the name of a group in AWS Cognito User Pool. If users are members of this group, they are assigned User role in Puddle.
auth.awsCognito.implicitGrantshould be true/false and is false by default. If true, then users are allowed access to Puddle (using user role) even if they are not members of Administrators nor Users group. If false, then users must be members of at least one group to be allowed access to Puddle.
auth.ldap.enabledshould be true/false and is false by default. If true, then authentication using LDAP is enabled.
auth.ldap.hostshould be the LDAP server hostname.
auth.ldap.portshould be the port where LDAP is accessible, defaults to 389.
auth.ldap.skipTLSshould be true/false and is false by default. If true then do not use TLS.
auth.ldap.useSSLshould be true/false and is true by default. If true, then use SSL.
auth.ldap.insecureSkipVerifyshould be true/false and is false by default. If true, then skip the server’s certificate verification.
auth.ldap.serverNameshould be the server name from server’s certificate. Defaults to auth.ldap.host.
auth.ldap.baseDNshould be the BaseDN where authentication search will start.
auth.ldap.bindDNshould be the BindDN used by Puddle to query LDAP.
auth.ldap.bindPasswordshould be the password of the user used by Puddle to query LDAP.
auth.ldap.bindAllowAnonymousLoginshould be true/false and is false by default. If true, then bind won’t be executed before getting user’s groups.
auth.ldap.authenticationFiltershould be the filter used when authenticating user. Defaults to"(uid=%s)".
auth.ldap.authorizationFlowshould be userAttribute | groupAttribute. Defaults to userAttribute. Based on the value, either attribute of group (for example member) of attribute of user (for example memberOf) will be used in authorization.
auth.ldap.authorizationFiltershould be the filter used when querying user’s groups. Defaults to"(memberOf=%s)".
auth.ldap.authorizationSearchValueAttributeshould be name of the attribute used during authorization. Defaults todn.
auth.ldap.uidAttributeNameshould be the name of the uid attribute. Defaults to uid. Value of uid attribute cannot be empty. Values of uid and uid number create unique identifier of the user.
auth.ldap.uidNumberAttributeNameshould be the name of the uid number attribute. Defaults to uidnumber. Value of uid number attribute cannot be empty. Values of uid and uid number create unique identifier of the user.
auth.ldap.emailAttributeNameshould be the name of the email attribute. Defaults to email. Value of email attribute might be empty.
auth.ldap.implicitGrantshould be true/false and is false by default. If true, then users are allowed access to Puddle (using user role) even if they are not members of Administrators nor Users group. If false, then users must be members of at least one group to be allowed access to Puddle.
auth.ldap.adminsGroupshould be the name of the Administrators group. Users in this group are assigned Administrator role in Puddle, users in Administrators group and Users group are considered Administrators.
auth.ldap.usersGroupshould be the name of the Users group. Users in this group are assigned User role in Puddle, users in Administrators group and Users group are considered Administrators.
auth.ldap.cloudResourcesTagsMappingshould be a mapping from LDAP attributes to tags of provisioned cloud resources. The values of the specified LDAP tags are used as values for the specified cloud tags. User cannot change these and they are applied to every system a user launches.
auth.oidc.enabledshould be true/false and is false by default. If true, then authentication using OpenID Connect is enabled.
auth.oidc.issuershould be the issuer of the tokens.
auth.oidc.clientIdshould be the clientId used by Puddle.
auth.oidc.clientSecretoptional clientSecret used by Puddle.
auth.oidc.redirectUrlshould be the redirect URL, defaults to /oicd/authorization-code/callback.
auth.oidc.scopesshould be the list of required scopes, defaults to openid, profile, email
auth.oidc.implicitGrantshould be true/false and is false by default. If true, then users are allowed access to Puddle (using user role) even if they are not members of Administrators nor Users group. If false, then users must be members of at least one group to be allowed access to Puddle.
auth.oidc.adminRoleshould be the name of the Administrators role. Users with this role are assigned Administrator role in Puddle, users with Administrator role and User role are considered Administrators.
auth.oidc.userRoleshould be the name of the Users role. Users with this role are assigned User role in Puddle, users with Administrator role and User role are considered Administrators.
packer.pathshould point to the packer binary. Defaults to/opt/h2oai/puddle/deps/packer.
packer.usePublicIPshould be true/false and is true by default. If true then packer will create VMs with public IP addresses, otherwise private IP will be used.
packer.buildTimeoutHoursshould be the number of hours after which the packer build times out. Default is 1 hour.
packer.nvidiaDriversURLif some custom URL for downloading NVIDIA drivers is required, for example because of internet access restrictions, set it here. Make sure to use version 440.59. Defaults to http://us.download.nvidia.com/XFree86/Linux-x86_64/440.59/NVIDIA-Linux-x86_64-440.59.run. For local files use file:///absolute-path/to/required.file.
packer.cudaURLif custom URL for downloading NVIDIA CUDA 10.0 is required, for example because of internet access restrictions, set it here. Make sure to use version 10.0 runfile(local). Defaults to https://developer.nvidia.com/compute/cuda/10.0/Prod/local_installers/cuda_10.0.130_410.48_linux. For local files use file:///absolute-path/to/required.file.
packer.cudnnURLif custom URL for downloading CUDnn is required, for example because of internet access restrictions, set it here. Make sure to use version 7.6.0.64. Defaults to https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1604/x86_64/libcudnn7_7.6.0.64-1+cuda10.0_amd64.deb. For local files use file:///absolute-path/to/required.file.
packer.cudnnDevURLif custom URL for downloading CUDnn-dev is required, for example because of internet access restrictions, set it here. Make sure to use version 7.6.0.64. Defaults to https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1604/x86_64/libcudnn7-dev_7.6.0.64-1+cuda10.0_amd64.deb. For local files use file:///absolute-path/to/required.file.
packer.terraformURLif custom URL for downloading Terraform is required, for example because of internet access restrictions, set it here. Make sure to use version 0.11.14. Defaults to https://releases.hashicorp.com/terraform/0.11.14/terraform_0.11.14_linux_amd64.zip. For local files use file:///absolute-path/to/required.file.
packer.driverlessAIURLPrefixif custom URL for downloading Driverless AI is required, for example because of internet access restrictions, set it here. For local directory containing Driverless AI installers use file:///absolute-path/to/dir/.
packer.h2o3URLPrefixif custom URL for downloading H2O-3 is required, for example because of internet access restrictions, set it here. For local directory containing H2O-3 installers use file:///absolute-path/to/dir/.
terraform.pathshould point to the terraform binary. Defaults to/opt/h2oai/puddle/deps/terraform.
terraform.usePublicIPshould be true/false and is true by default. If true then terraform will use public IP to communicate with the provisioned Virtual machines, otherwise private IP will be used.
terraform.pluginDiroptional path where Terraform plugins are stored. If set, Terraform will not try to download plugins during initialization.
reverseProxy.enabledshould be true/false and is false by default. If true then reverse proxy is used.
reverseProxy.portshould be port where reverse proxy is running, defaults to 1234.
reverseProxy.caCertificateshould be path to the CA certificate used to issue HTTPS certificates for systems provisioned by Puddle. Must be a PEM encoded certificate with no password protection.
reverseProxy.caPrivateKeyshould be path to the CA private key. Must be a PEM encoded private key with no password protection.
reverseProxy.clientCertificateshould be path to the certificate used when doing forward auth (relevant for H2O-3 systems). Must be a PEM encoded certificate with no password protection.
reverseProxy.clientPrivateKeyshould be path to the private key used when doing forward auth (relevant for H2O-3 systems). Must be a PEM encoded private key with no password protection.
backend.baseURLshould be the URL where Puddle is running, for example https://puddle.h2o.ai.
backend.connections.usePublicIpshould be true/false and is true by default. If true then backend will use public IP to communicate with the provisioned Virtual machines, otherwise private IP will be used.
webclient.usePublicIpshould be true/false and is true by default. If true then public IP is shown in UI, otherwise private IP is displayed.
webclient.outOfCUsUserMsgshould be a message displayed to users when they try to create or start a system, but there are not enough Compute Units available.
webclient.userSshAccessEnabledshould be true/false and is true by default. If true then users are able to download SSH keys of the provisioned VMs.
providers.azure.enabledshould be true/false and is false by default. If true then Microsoft Azure is enabled as provider in Puddle. All variables underproviders.azuremust be set if enabled.
providers.azure.authorityshould be set tohttps://login.microsoftonline.com/<Azure ActiveDirectory Name>.onmicrosoft.com. The Azure Active Directory name can be found in following way:
- Go to Azure Active Directory blade.
- Select Overview.
providers.azure.locationshould be set to the same value that was specified for the Resource group, for exampleeastus.
providers.azure.rgshould be set to the name of the newly created Resource group.
providers.azure.vnetrgshould be set to the name of the Resource group where VNET and Subnet are present.
providers.azure.vnetshould be set to the id of the newly created Virtual network.
providers.azure.sgshould be set to the id of the newly created Network security group.
providers.azure.subnetshould be set to the id of the newly created Subnet.
providers.azure.enterpriseApplicationObjectIdshould be the Object ID of the Enterprise Application. The Enterprose Application Object ID can be found in following way:
- Go to the Azure Active Directory blade.
- Select Enterprise Applications.
- Select the newly created Enterprise Application.
- Use the Object ID.
providers.azure.adminRoleIdshould be set to the ID of the newly created Administator Role in the Application Registration Manifest. The Administator Role ID can be found in following way:
- Go to the Azure Active Directory blade.
- Select App registrations (preview).
- Select the newly created App registration.
- Select Manifest.
- Search for Administator role under appRoles and use the ID of this role.
providers.azure.publicIpEnabledshould be true/false and is true by default. Public IP is created if and only if this is set to true. Must be set to true if at least one of packer, terraform, backend or webclient uses public IP.
providers.azure.packerInstanceTypeshould be the instance type used by Packer to build images. Defaults to Standard_NC6.
providers.azure.sshUsernameshould be the username used when doing SSH/SCP from backend. Defaults to puddle.
providers.azure.sourceSharedImageGallery.subscriptionIdID of the subscription where the Shared Image Gallery with image used as source is present. Leave empty or remove if other image source should be used.
providers.azure.sourceSharedImageGallery.rgname of the resource group where the Shared Image Gallery with image used as source is present. Leave empty or remove if other image source should be used.
providers.azure.sourceSharedImageGallery.namename of the Shared Image Gallery with image used as source is present. Leave empty or remove if other source should be used.
providers.azure.sourceSharedImageGallery.imageNamename of the Image from Shared Image Gallery to use as source. Leave empty or remove if other source should be used.
providers.azure.sourceSharedImageGallery.imageVersionversion of the Image from Shared Image Gallery to use as source. Leave empty or remove if other source should be used.
providers.azure.sourceImageRGname of the resource group containing the private image used as the source for newly built Puddle images. Leave empty or remove if other source should be used.
providers.azure.sourceImageNamename of the private image which should be used as the source for newly built Puddle images. Leave empty or remove if other source should be used.
providers.azure.sourceImagePublisherignored if other source image is set as well (for example private image, or image from Shared Image Gallery). Should be the name of the publisher of the image used as source for newly built Puddle images. Defaults to Canonical. Leave empty or remove if other source should be used.
providers.azure.sourceImageOfferignored if other source image is set as well (for example private image, or image from Shared Image Gallery). Should be the name of the offering of the publisher used as source for newly build Puddle images. Defaults to UbuntuServer. Leave empty or remove if other source should be used.
providers.azure.sourceImageSkuignored if other source image is set as well (for example private image, or image from Shared Image Gallery). Should be the image sku used as source for newly built Puddle images. Defaults to 16.04-LTS. Leave empty or remove if other source should be used.
providers.azure.imageTagsmap of tags used for all Packer resources and produced Image.
providers.azure.customDataScriptPathoptional path to script with custom data to supply to the machine when provisioning new system. This can be used as a cloud-init script.
providers.azure.packerCustomDataScriptPathoptional path to script with custom data to supply to the machine when building new image. This can be used as a cloud-init script.
providers.azure.storageDiskLunshould be the LUN of the storage data disk, defaults to 0.
providers.azure.storageDiskFileSystemshould be the filesystem used with storage data disk, default to ext4.
providers.azure.storageDiskDeviceshould be the path to the device used as a storage data disk, defaults to /dev/sdc.
providers.aws.enabledshould be true/false and is false by default. If true then Amazon AWS is enabled as provider in Puddle. All variables underproviders.awsmust be set if enabled.
providers.aws.ownershould be the owner of the newly created resources.
providers.aws.vpcIdshould be the ID of the VPC where Virtual machines will be launched.
providers.aws.sgIdsshould be the list of IDs of the Security Groups applied to provisioned Virtual machines.
providers.aws.subnetIdshould be the ID of the Subnet where Virtual machines will be placed.
providers.aws.iamInstanceProfileshould be the name of the IAM Instance Profile assigned to the Virtual machines.
providers.aws.publicIpEnabledshould be true/false and is false by default. If true, then no public IP will be assigned. Must be set to true if at least one of packer, terraform, backend or webclient uses public IP.
providers.aws.packerInstanceTypeshould be the instance type used by packer to build images, defaults to p3.2xlarge.
providers.aws.encryptEBSVolumeshould be true/false and is false by default. If true then EBS Volumes are encrypted using KMS Key. The KMS Key is unique for every system.
providers.aws.ebsKMSKeyArn`should be the arn of KMS key used to encrypt all VMs. If this is empty then a new KMS is created for every VM.
providers.aws.metadataEndpointIAMRoleshould be URL which is used to check assigned IAM role. Defaults to http://169.254.169.254/latest/meta-data/iam/info.
providers.aws.suppressIAMRoleCheckshould be true/false and is false by default. If true then Puddle does not try to obtain assigned IAM role from AWS Metadata endpoint.
providers.aws.sourceAMIOwnerowner of the AMI used as source for newly built Puddle AMIs. Defaults to 099720109477 (Canonical).
providers.aws.sourceAMINameFiltername of the image, with wildcards, which should be used as source for newly built Puddle images. Defaults to ubuntu/images/ubuntu-xenial-16.04-amd64-server-.
providers.aws.packerRunTagsmap of tags used for Packer EC2 instance and Volume. These tags are not applied to produced AMI.
providers.aws.amiTagsmap of tags used for AMIs built by Puddle.
providers.aws.userDataScriptPathoptional path to script with custom user data script which should be used when launching new systems.
providers.aws.packerUserDataScriptPathoptional path to script with custom user data script which should be used when building new images.
providers.aws.storageEBSDeviceNameshould be the device name used when attaching EBS Volume, defaults to /dev/sdf
providers.aws.storageDiskFileSystemshould be the filesystem used with storage data disk, default to ext4.
providers.aws.storageDiskDeviceshould be the path to the device used as a storage data disk, defaults to /dev/nvme1n1.
providers.gcp.enabledshould be true/false and is false by default. If true then Google GCP is enabled as provider in Puddle. At least the variablesproviders.gcp.projectandproviders.gcp.zonemust be set if enabled.
providers.gcp.projectshould be id of the project that will host the newly created resources.
providers.gcp.zoneshould be the GCE Zone that will host the newly created resources.
providers.gcp.networkshould be the name of the network that will host the newly created VMs, defaults to “default”. Optional ifproviders.gcp.subnetworkis set (needs to point to the subnet’s network).
providers.gcp.subnetworkshould the name of the subnetwork that will host the newly created VMs, required for custom subnetmode networks, has to be in a region that includesproviders.gcp.zone, has to be inproviders.gcp.networkif specified (incl. the default), defaults to empty.
providers.gcp.publicIpEnabledshould be true/false and is false by default. If true, then no public IP will be assigned to Puddle-managed VMs. Must be set to true if at least one of packer, terraform, backend or webclient uses public IP.
providers.gcp.encryptVolumeshould be true/false and is false by default. If true, all systems’ VM volumes will be encrypted. If true, eitherproviders.gcp.volumeKmsKeyIdorproviders.gcp.volumeKmsKeyRingNameandproviders.gcp.volumeKmsKeyRingLocationhave to be set.
providers.gcp.volumeKmsKeyIdshould be the full resource name of the key used to encrypt all VMs, for example projects/XXX/locations/XXX/keyRings/XXX/cryptoKeys/XXX. If empty andproviders.gcp.encryptVolumeis true then a new KMS is created for every system, defaults to empty.
providers.gcp.volumeKmsKeyRingNameshould be the name of the KMS key ring in which unique volume KMS keys will be created. Ignored ifproviders.gcp.volumeKmsKeyIdis set.
providers.gcp.volumeKmsKeyRingLocationshould be the location of the KMS key ring in which unique volume KMS keys will be created. Ignored ifproviders.gcp.volumeKmsKeyIdis set.
providers.gcp.serviceAccountEmailshould be the service account used for Puddle system VMs, uses the default GCE service account if empty, defaults to empty.
providers.gcp.sshUsernameshould be the username for SSH/SCP, defaults to “puddle”.
providers.gcp.storageDiskFileSystemshould be the file system name used for storage disks (must be compatible withmkfson the image), defaults to “ext4”.
providers.gcp.startupScriptPathoptional path to script used as input for startup script (cloud init).
providers.gcp.imageLabelsshould be map of labels to be applied to the images built by Puddle, see https://cloud.google.com/compute/docs/labeling-resources for value restrictions.
providers.gcp.packerServiceAccountEmailshould be the service account used for Puddle Packer VMs, uses the default GCE service account if empty, defaults to empty.
providers.gcp.packerSourceImageProjectshould be the project that hosts the image family to be used as source for newly built Puddle images, defaults to “ubuntu-os-cloud”.
providers.gcp.packerSourceImageFamilyshould be the image family that should be used as source for newly built Puddle images, defaults to “ubuntu-1604-lts”.
providers.gcp.packerInstanceTypeshould be the machine type used by Packer to build images, defaults to “n1-highmem-8”.
providers.gcp.packerAcceleratorTypeshould be the type of accelerators to be attached to the VM used by Packer to build images, defaults to “nvidia-tesla-v100”. Needs to be available inproviders.gcp.zone.
providers.gcp.packerAcceleratorCountshould be the number of accelerators to be attached to the VM used by Packer to build images, must be >= 0, defaults to 1.
providers.gcp.packerStartupScriptPathoptional path to script used as input for startup script (cloud init) in packer VMs.
providers.gcp.packerRunLabelsshould be map of tags used for Packer VMs and Volumes, these tags are not applied to the resulting image, see https://cloud.google.com/compute/docs/labeling-resources for value restrictions.
products.dai.configTomlTemplatePathshould be the path to custom config.toml file, which will be used as default configuration for all new Driverless AI Systems. If not set, the default file is used.
products.dai.licenseshould be the path to DriverlessAI license file. If set, then this license will be automatically installed on all provisioned systems.
products.h2o3.authEnabledshould be true/false and is false by default. If true the H2O-3 has Basic Auth enabled. Use of reverse proxy is recommended in this case to enable one-click login to H2O-3.
logs.dirshould be set to a directory where logs should be placed.
logs.maxSizeshould be the max size of log file, in MB, defaults to 1000.
logs.maxBackupsshould be the number of old files retained, defaults to 15.
logs.maxAgeshould be the max age of retained files, in days, defaults to 60. Older files are always deleted.
logs.compressshould be true/false and is true by default. If true then the files will be compressed when rotating.
logs.levellog level to use, should be trace/debug/info/warning/error/fatal and is trace by default.
mailing.enabledshould be true/false. If true then mailing is enabled. All fields undermailingare mandatory if this is set to true.
mailing.servershould be the hostname and port of the SMTP server, for example smtp.example.com:587.
mailing.usernameshould be the client username.
mailing.passwordshould be the client password.
mailing.fromAddressshould be the email address used as FROM, for example in case of an address ‘<Puddle> puddle@h2o.ai’ this field should be set to puddle@h2o.ai.
mailing.fromNameshould be the name used as FROM, defaults to Puddle, for example in case of an address ‘<Puddle> puddle@h2o.ai’ this field should be set to Puddle.
mailing.recipientsshould be the space-separated list of recipients.
mailing.offsetHoursshould be a number of hours between repeated email notifications, defaults to 24, does not apply to FAILED system notifications.
Configuring Environment Variables¶
The next step is to to fill in the variables in EnvironmentFile file, which is located at /etc/puddle/EnvironmentFile. The EnvironmentFile should contain the following:
# Should point to dir with config.yaml
PUDDLE_config_dir='/etc/puddle/'
# AzureRM Provider should skip registering the Resource Providers
ARM_SKIP_PROVIDER_REGISTRATION=true
# Azure related environment variables, please fill-in all values if you use Azure as provider
# AZURE_SUBSCRIPTION_ID='YOUR-SUBSCRIPTION-ID'
# AZURE_TENANT_ID='YOUR-TENANT-ID'
# AZURE_CLIENT_ID='YOUR-CLIENT-ID'
# AZURE_CLIENT_SECRET='YOUR-CLIENT-SECRET'
# AWS related environment variables, please fill-in all values if you use AWS as provider
# AWS_ACCESS_KEY_ID='YOUR-AWS-ACCESS-KEY-ID'
# AWS_SECRET_ACCESS_KEY='YOUR-AWS-SECRET-ACCESS-KEY'
# AWS_REGION='AWS-REGION'
# General variables, delete those which are not necessary
# http_proxy=http://10.0.0.100:3128
# https_proxy=http://10.0.0.100:3128
# no_proxy=localhost,127.0.0.1
PUDDLE_config_dirdirectory where the config.yaml file is present.ARM_SKIP_PROVIDER_REGISTRATION- AzureRM Provider should skip registering the Resource Providers. This should be left as true.AZURE_SUBSCRIPTION_IDis the ID of the subscription that should be used. This value can be found in following way:- Search for Subscriptions.
- Use the SUBSCRIPTION ID of the subscription you want to use.
AZURE_TENANT_IDis ID of tenant that should be used. This value can be found in following way:- Select Azure Active Directory blade.
- Select App registrations (preview).
- Select the newly created App registration.
- Use Directory (tenant) ID.
AZURE_CLIENT_IDis the Application ID that should be used. This value can be found in following way:- Select Azure Active Directory blade.
- Select App registrations (preview).
- Select the newly created App registration.
- Use Application (client) ID.
AZURE_CLIENT_SECRETclient secret that should be used. This value can be found in following way:- Select the Azure Active Directory blade.
- Select App registrations (preview).
- Select the newly created App registration.
- Select Certificates & Secrets.
- Click New client secret.
- Fill in the form and click Add.
- The secret value should be visible. Copy it because after refreshing the page, this value is gone and cannot be restored.
AWS_ACCESS_KEY_IDAWS Access Key Id used by Puddle to access the AWS services.AWS_SECRET_ACCESS_KEYAWS Secret Access Key used by Puddle to access the AWS services.AWS_REGIONAWS Region used by Puddle to access the AWS services.http_proxyis the URL of proxy server to be used (if required), for example http://10.0.0.3:3128.https_proxyis the URL of proxy server to be used (if required), for example http://10.0.0.3:3128.no_proxyis the comma-separated list of hosts that should be excluded from proxying, for example localhost,127.0.0.1.
Note that you don’t need to enter credentials on GCP by default, since Puddle uses application default credentials (i.e., the VM service account).
Running Puddle¶
After all of the previous steps are successfully completed, we can now start Puddle. Execute the following command to start the server and web UI:
systemctl start puddle
Puddle is accessible on port 443 if HTTPS is enabled, or on port 80 if HTTP is being used.
First Steps¶
At first, you will have to perform some initialization steps:
- Log in to Puddle as the Administrator.
- Go to Administration > Check Updates.
- Either use the update plan from the default URL location, or specify a custom update plan file.
- Click Submit.
- Review the plan and click Apply.
- Go to Administration > Images.
- Build all the images you want to use. Please be aware this can take up to 1 hour.
Once the images are built, your Puddle instance is ready.
Stats Board (Optional)¶
The stats board is an optional component. It’s distributed as Python wheel, and it requires Python 3.6. It’s recommended (although not necessary) to run the board inside a virtual environment.
Use the following to install the required dependencies:
apt install gcc libpq-dev python3.6-dev python-virtualenv
yum install epel-release
yum install gcc postgresql-devel python36-devel python-virtualenv
Use the following to create the virtualenv:
mkdir -p /opt/h2oai/puddle/envs
cd /opt/h2oai/puddle/envs
virtualenv -p python3.6 puddle-stats-env
Please make sure that the virtualenv uses the same name and is available at the same path as in this provided snippet. Otherwise the systemd script used to manage Stats Board will not work.
Use the following to install the stats board. Please note that this command will install dependencies as well:
source /opt/h2oai/puddle/envs/puddle-stats-env/bin/activate
pip install puddle_stats_board-<VERSION>-py3-none-any.whl
Use the following to run the stats board:
systemctl start puddle-dashboard
The stats board is running on port 8050 and is accessible from Puddle UI at http://<PUDDLE_SERVER_ADDRESS>/board. There is a link in the Administration menu as well.