Install on Amazon ECS Enterprise¶
Run DataOps Data Quality TestGen Enterprise as an Amazon ECS service on AWS Fargate, with the application database on Amazon RDS for PostgreSQL.
To run it on ECS, you create a task definition for the service, a one-time database setup task, the service, and a load balancer.
Prerequisites¶
- Request access to the private enterprise Docker image from your DataKitchen representative.
- Install the AWS CLI and Docker with Buildx.
- Choose the domain names for the TestGen UI and for the API and MCP server, or one domain to serve TestGen under a path, and have a certificate in AWS Certificate Manager covering them.
AWS resources¶
- An ECS cluster that runs Fargate tasks.
- A VPC with private subnets in at least two Availability Zones. The task subnets need outbound access to Amazon ECR, AWS Secrets Manager, and CloudWatch Logs, through a NAT gateway or VPC endpoints, and to your target databases and, for email notifications, your SMTP server.
- An Amazon ECR repository for the TestGen image.
PostgreSQL server¶
- Amazon RDS for PostgreSQL 14 or later, reachable from the task subnets on port
5432. - Recommended compute: 4 vCPUs and 128 GB disk, for example, db.m6g.xlarge.
Prepare the application database¶
Connect to the RDS instance with its master user and create the user that TestGen will use.
The CREATEDB privilege is required: during setup, TestGen creates its datakitchen database and the testgen schema.
Note
Do not configure TestGen with the RDS master user. RDS can rotate its password, and a running TestGen task keeps the old one until it restarts.
Copy the image to Amazon ECR¶
The enterprise image supports both the linux/amd64 and linux/arm64 platforms. Copy the image with docker buildx imagetools create, which copies every platform the image supports.
-
Sign in to Docker Hub with the credentials provided by your DataKitchen representative, and to your ECR registry.
-
Copy the version you are installing. Use an exact version rather than a major version such as
v5. For a list of recent releases, see TestGen Release Notes.
Store the secrets¶
Store the sensitive values in one AWS Secrets Manager secret. The task definitions inject each one.
-
Create the secret, replacing the placeholders. Use the password of the
testgenuser forTG_METADATA_DB_PASSWORD, and generate a random value for each of the others.aws secretsmanager create-secret --name testgen/app --secret-string '{ "TG_METADATA_DB_PASSWORD": "<postgres password>", "TG_DECRYPT_SALT": "<random string>", "TG_DECRYPT_PASSWORD": "<random string>", "TG_JWT_HASHING_KEY": "<base64-encoded random 32 bytes>", "TESTGEN_PASSWORD": "<initial admin password>" }'Warning
Keep a copy of these values, and do not enable automatic rotation for this secret. If
TG_DECRYPT_SALTorTG_DECRYPT_PASSWORDis lost or changed, the credentials of every database connection must be re-entered. IfTG_JWT_HASHING_KEYchanges, every user is signed out. -
Give the task execution role permission to read the secret, in addition to the
AmazonECSTaskExecutionRolePolicymanaged policy.
Register the task definitions¶
TestGen uses two task definitions from the same image: one for the service, and one that you run once to set up the application database.
-
Create a
testgen-task.jsonfile and replace the placeholders. Keep this file: an upgrade registers a new revision of it.{ "family": "testgen", "requiresCompatibilities": ["FARGATE"], "networkMode": "awsvpc", "cpu": "4096", "memory": "16384", "runtimePlatform": { "operatingSystemFamily": "LINUX", "cpuArchitecture": "X86_64" }, "executionRoleArn": "<task execution role ARN>", "containerDefinitions": [ { "name": "migrate", "image": "<ECR repository URI>:v<version>", "essential": false, "command": ["upgrade-system-version"], "environment": [ { "name": "TG_METADATA_DB_HOST", "value": "<postgres host>" }, { "name": "TG_METADATA_DB_USER", "value": "testgen" } ], "secrets": [ { "name": "TG_METADATA_DB_PASSWORD", "valueFrom": "<secret ARN>:TG_METADATA_DB_PASSWORD::" }, { "name": "TG_DECRYPT_SALT", "valueFrom": "<secret ARN>:TG_DECRYPT_SALT::" }, { "name": "TG_DECRYPT_PASSWORD", "valueFrom": "<secret ARN>:TG_DECRYPT_PASSWORD::" }, { "name": "TG_JWT_HASHING_KEY", "valueFrom": "<secret ARN>:TG_JWT_HASHING_KEY::" } ], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "/ecs/testgen", "awslogs-region": "<region>", "awslogs-stream-prefix": "migrate" } } }, { "name": "testgen", "image": "<ECR repository URI>:v<version>", "essential": true, "dependsOn": [{ "containerName": "migrate", "condition": "SUCCESS" }], "stopTimeout": 90, "portMappings": [ { "containerPort": 8501, "protocol": "tcp" }, { "containerPort": 8530, "protocol": "tcp" } ], "environment": [ { "name": "TG_METADATA_DB_HOST", "value": "<postgres host>" }, { "name": "TG_METADATA_DB_USER", "value": "testgen" }, { "name": "TG_INSTANCE_ID", "value": "<instance name>" }, { "name": "TG_UI_BASE_URL", "value": "https://<UI domain>" }, { "name": "TG_BASE_URL", "value": "https://<API domain>" } ], "secrets": [ { "name": "TG_METADATA_DB_PASSWORD", "valueFrom": "<secret ARN>:TG_METADATA_DB_PASSWORD::" }, { "name": "TG_DECRYPT_SALT", "valueFrom": "<secret ARN>:TG_DECRYPT_SALT::" }, { "name": "TG_DECRYPT_PASSWORD", "valueFrom": "<secret ARN>:TG_DECRYPT_PASSWORD::" }, { "name": "TG_JWT_HASHING_KEY", "valueFrom": "<secret ARN>:TG_JWT_HASHING_KEY::" } ], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "/ecs/testgen", "awslogs-region": "<region>", "awslogs-stream-prefix": "testgen" } } } ] }The
migratecontainer upgrades the application database before thetestgencontainer starts. KeepstopTimeoutat90or higher, so that running profiling jobs can pause when the task stops. For what each variable does, see the Environment variables reference.TestGen profiles and tests DuckDB databases and file data sources with the task's own memory and disk. If you plan to connect them, see Size TestGen for DuckDB and File Data Sources. For more memory, raise
cpuandmemoryto a combination that Fargate supports. For more disk, add"ephemeralStorage": { "sizeInGiB": <size> }. -
Create a
testgen-setup-task.jsonfile and replace the placeholders. It runs once, so it has a single container.{ "family": "testgen-setup", "requiresCompatibilities": ["FARGATE"], "networkMode": "awsvpc", "cpu": "4096", "memory": "16384", "runtimePlatform": { "operatingSystemFamily": "LINUX", "cpuArchitecture": "X86_64" }, "executionRoleArn": "<task execution role ARN>", "containerDefinitions": [ { "name": "setup", "image": "<ECR repository URI>:v<version>", "essential": true, "command": ["setup-system-db", "--yes"], "environment": [ { "name": "TG_METADATA_DB_HOST", "value": "<postgres host>" }, { "name": "TG_METADATA_DB_USER", "value": "testgen" }, { "name": "TESTGEN_USERNAME", "value": "admin" } ], "secrets": [ { "name": "TG_METADATA_DB_PASSWORD", "valueFrom": "<secret ARN>:TG_METADATA_DB_PASSWORD::" }, { "name": "TESTGEN_PASSWORD", "valueFrom": "<secret ARN>:TESTGEN_PASSWORD::" }, { "name": "TG_DECRYPT_SALT", "valueFrom": "<secret ARN>:TG_DECRYPT_SALT::" }, { "name": "TG_DECRYPT_PASSWORD", "valueFrom": "<secret ARN>:TG_DECRYPT_PASSWORD::" }, { "name": "TG_JWT_HASHING_KEY", "valueFrom": "<secret ARN>:TG_JWT_HASHING_KEY::" } ], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "/ecs/testgen", "awslogs-region": "<region>", "awslogs-stream-prefix": "setup" } } } ] } -
Create the log group, and register both task definitions.
Set up the database¶
Run the setup task once, before the service's first start. It creates the datakitchen database and the initial system administrator account, and takes about two minutes.
aws ecs run-task --cluster <cluster> --launch-type FARGATE \
--task-definition testgen-setup \
--network-configuration "awsvpcConfiguration={subnets=[<private subnet IDs>],securityGroups=[<task security group ID>]}"
The setup container exits with code 0 and logs setup-system-db has successfully finished. when it succeeds.
Warning
Run the setup task only once. Against a database that is already set up, it stops with relation ... already exists. If the setup fails partway, drop the database before running it again.
After a successful install, deregister the setup task definition so that it cannot be run again by mistake.
Create the load balancer¶
TestGen serves the UI on port 8501 and the API and MCP server on port 8530. Create an Application Load Balancer that forwards each domain to its port.
To serve TestGen under a path on a domain shared with other applications, use the health check paths and path-based rules in Serve TestGen Through a Reverse Proxy instead of the health check paths in step 1 and the domain rules in step 2.
-
Create two target groups with target type
ip, one for each port, with these health checks.Port Health check path Success codes 8501/_stcore/health2008530/api/v1/health200 -
Create the load balancer in your VPC, with an HTTPS listener using your certificate. Add a rule that forwards
<UI domain>to the8501target group and<API domain>to the8530target group. - Set the load balancer's idle timeout to
90seconds. - Allow inbound traffic on ports
8501and8530to the task security group from the load balancer's security group. - Create DNS records pointing the UI and API domains at the load balancer.
Create the service¶
Create the service with one task. TestGen does not support more than one task.
aws ecs create-service --cluster <cluster> --service-name testgen \
--task-definition testgen --launch-type FARGATE --desired-count 1 \
--deployment-configuration "minimumHealthyPercent=0,maximumPercent=100,deploymentCircuitBreaker={enable=true,rollback=false}" \
--health-check-grace-period-seconds 180 \
--network-configuration "awsvpcConfiguration={subnets=[<private subnet IDs>],securityGroups=[<task security group ID>]}" \
--load-balancers \
"targetGroupArn=<8501 target group ARN>,containerName=testgen,containerPort=8501" \
"targetGroupArn=<8530 target group ARN>,containerName=testgen,containerPort=8530"
minimumHealthyPercent=0,maximumPercent=100stops the running task before starting its replacement, so two tasks never run at once. TestGen is unavailable for a few minutes during each deployment.rollback=falsekeeps ECS from restarting the previous version, which may not run on an upgraded application database.
When the targets are healthy, open https://<UI domain> in a browser and sign in as admin with the TESTGEN_PASSWORD value from the secret.
Tip
To configure email notifications and other settings, see Administer TestGen, and apply the settings as in Change settings. To set up single sign-on, see Enable single sign-on.
Upgrade TestGen¶
- In the TestGen UI, check the Profiling Runs and Test Runs pages to ensure there are no actively running processes.
- Copy the new version to ECR, as in Copy the image to Amazon ECR. For a list of recent releases, see TestGen Release Notes.
-
In
testgen-task.json, set bothimagevalues to the new version, and register the new revision. -
Update the service to the new revision.
The new task upgrades the application database before TestGen starts.
Change settings¶
To set an environment variable, such as the email server settings in Configure Email Server:
- Add the variable to the
environmentlist of thetestgencontainer intestgen-task.json. For a password or another sensitive value, add it to the secret instead, and reference it in the container'ssecretslist. - Register the new revision, and update the service to it, as in Upgrade TestGen.
Stop, start, and restart¶
# Stop
aws ecs update-service --cluster <cluster> --service testgen --desired-count 0
# Start
aws ecs update-service --cluster <cluster> --service testgen --desired-count 1
# Restart
aws ecs update-service --cluster <cluster> --service testgen --force-new-deployment
Read the logs¶
The task definition sends the output of each container to the /ecs/testgen log group in CloudWatch Logs. To save the last day of logs to a file, for example to send to support:
The application and audit log files in /var/lib/testgen/log are on the task's own storage, and are lost whenever the task is replaced. To keep them, for example to collect audit records, mount an Amazon EFS volume at /var/lib/testgen/log through an access point whose POSIX user is the container's testgen user (UID 100, GID 101), and whose root directory is created with that owner. See Collect Audit Records.
Provide files to the container¶
Some settings point to a file in the container, such as the RDS certificate bundle or the sso_auth.toml file for single sign-on. Provide these files on an Amazon EFS volume, mounted in each container that reads them.
Encrypt the connection to the application database¶
To require a verified TLS connection to RDS, add these variables to the migrate and testgen containers, and to the setup container if you have not installed yet.
{ "name": "TG_METADATA_DB_SSLMODE", "value": "verify-full" },
{ "name": "TG_METADATA_DB_SSLROOTCERT", "value": "/dk/certs/rds-ca.pem" }
The image's trust store does not include the RDS certificate authority. Provide the certificate bundle for your region at that path, in each of those containers.
Enable single sign-on¶
Create the sso_auth.toml file and set the variables as in Configure Single Sign-On. In the testgen container, provide the file at /dk/.streamlit/secrets.toml, and add the variables to the container's environment list.
Environment variables reference¶
| Variable | Description |
|---|---|
TG_METADATA_DB_HOST |
Endpoint of the RDS instance. |
TG_METADATA_DB_USER, TG_METADATA_DB_PASSWORD |
The user created in Prepare the application database. |
TG_DECRYPT_SALT, TG_DECRYPT_PASSWORD |
Encrypt the credentials of the database connections you configure. Set once; never change. |
TG_JWT_HASHING_KEY |
Signs user sessions and access tokens. Base64-encoded random 32 bytes. |
TESTGEN_USERNAME, TESTGEN_PASSWORD |
The initial system administrator account, read only by the setup task. After installing, sign in with these credentials to create accounts for your team. |
TG_INSTANCE_ID |
A name that identifies this TestGen instance. |
TG_UI_BASE_URL |
The externally reachable URL of the UI. Include a path to serve the UI under it. |
TG_BASE_URL |
The externally reachable URL of the API and MCP server. Include a path to serve the API and MCP server under it. |
For other settings, see Set Environment Variables, and apply them as in Change settings.