Skip to main content
Version: 9.4

Deploy Qrvey v9.4

The following sections show how to deploy Qrvey v9.4. To reconfigure a Terraform-managed Qrvey cluster to use ArgoCD management, you can use a single deploy command to build and adopt the infrastructure. You can also apply a two-step approach (apply then adopt full) to each cloud.

The following information addresses the primary usage of these scripts with Docker.

Before You Begin

You need the following items in place before you can use these scripts with Docker.

  • Running Docker Desktop container.
  • Access to the qrveydev.azurecr.io registry.
  • A config.json (AWS) or config.yaml (Azure) file containing the required fields.

Configuration

Your config.json file should include the following fields as part of its structure. The following example presents a sample AWS configuration:

{
"account_config": {
"access_key_id": "AKIA...",
"secret_access_key": "...",
"region": "us-east-1",
"bucket": "qrvey-deploy-aws-terraform-states-...",
"key": "mp/deploy-aws/.../customer.tfstate"
},
"variables": {
"qrvey_chart_version": "<QRVEY_VERSION>",
"GITOPS_ADMIN_TOKEN": "ATATT3xFfGF0...",
"GITOPS_ADMIN_EMAIL": "user@company.com",
"customer_info": {
"email": "user@company.com",
"company": "customername"
},
"customer_repo": {
"auto_create_repo": true,
"provider": "bitbucket",
"org": "qrvey",
"name": "<deployment_id>-platform-control",
"deploy_key": ""
},
"registry_user": "qrveydev",
"registry_key": "..."
}
}

An Azure configuration uses the same variables block and uses the Azure shape (ARM credentials and Blob back end) in the account_config block:

{
"account_config": {
"ARM_CLIENT_ID": "...", "ARM_CLIENT_SECRET": "...",
"ARM_TENANT_ID": "...", "ARM_SUBSCRIPTION_ID": "...",
"resource_group_name": "qrvey-<id>-rg",
"storage_account_name": "qrveytf<id>",
"container_name": "tfstate", "key": "<id>.tfstate"
}
}

The following sections provide additional details for these fields.

account_config

This reference includes a bucket and key pointing to the S3 back end where the customer's Terraform state is stored. For Azure, the storage_account_name, container_name, and key point to the Blob back end.

qrvey_chart_version

This entry lists the OCI chart version for the main Qrvey application chart, and must match a tag actually published to the OCI registry. Contact the DevOps team to obtain the current value.

customer_repo

This entry defines the Git repository that holds the platform-control configuration.

ParameterSettings
auto_create_repoSet to true to trigger scripts to automatically create the repository.
providerSet to bitbucket, github, or gitlab.
orgAdd the organization or workspace that owns the repository.
nameAdd the repository name (convention: <deployment_id>-platform-control).
deploy_keyLeave this parameter empty. This is automatically populated by setup-repo.

GITOPS_ADMIN_TOKEN

This entry stores the API token used for Git operations (push, deploy key upload, repository creation).

ProviderToken TypeMinimum Permissions
BitbucketAPI Token (create here)read:repository:bitbucket, write:repository:bitbucket, admin:repository:bitbucket, write:ssh-key:bitbucket
GitHubClassic PATrepo scope.
GitLabPersonal Access Tokenapi scope.

GITOPS_ADMIN_EMAIL

This required entry stores the Git/Atlassian account email that owns GITOPS_ADMIN_TOKEN. Bitbucket uses the Basic-auth username for API calls and HTTPS pushes (GITOPS_ADMIN_EMAIL:GITOPS_ADMIN_TOKEN). Both must belong to the same account, or operations fail with a 403 Forbidden error.

The read:webhook:bitbucket and write:webhook:bitbucket webhook scopes are required because the setup repository registers an ArgoCD push-notification webhook on the platform-control repository at https://argocd.<deployment>.<dns_zone>/api/webhook. With the webhook in place, each Git push refreshes all affected applications within 25 seconds. Without it, ArgoCD reverts to a 3-minute polling cycle, which makes adopt upgrade-version and other ArgoCD workflows appear stalled because of the polling gap. Adoption proceeds without the webhook scopes, but the operator experience is affected, and the workflow requires a follow-up token rotation with the correct scopes.

registry_user / registry_key

This entry stores the OCI registry credentials used for Docker login and by Terraform to pull Helm charts.

Registry login:

jq -r '.variables.registry_key' config.json | \
docker login qrveydev.azurecr.io -u "$(jq -r '.variables.registry_user' config.json)" --password-stdin

Domain and Certificate Configuration

The dns_zone_name sets the hostname where the platform serves. Qrvey supports the following use cases:

Qrvey mp.qrveyapp.com Zone

Automatically returns <deployment_id>.mp.qrveyapp.com, which is applicable for most users. Qrvey creates the DNS record and the HTTPS certificate, automatically writing to the mp.qrveyapp.com zone.

Single Manual DNS Record

When using any other domain, (such as qrvey.me or a customer-owned domain), use a manual record entry:

"dns_zone_name": "analytics.acme.com"

Qrvey cannot write to that zone. During adoption, create the following records at your DNS provider:

analytics.acme.com          >  <load-balancer>  (CNAME for a hostname)
argocd.analytics.acme.com > <load-balancer> (CNAME for a hostname)

The HTTPS certificate issues automatically when these records are resolved.

Installation Options

Qrvey offers the following installation options.

The unified image bundles the AWS and Azure Terraform trees, adoption and recovery scripts, Copier templates, and CLIs, and automatically detects the target cloud from your configuration. Its deploy verb runs terraform apply and adopt full in the same process. The tag applies to multiple architectures (linux/amd64 and linux/arm64), so Docker uses the architecture matching your machine automatically.

After you have set up your config.json file and registry login, run the following commands:

touch terraform-output.yaml

If missing during the bind mount, Docker creates terraform-output.yaml as a directory (not a file).

mkdir work
IMAGE=qrveydev.azurecr.io/qrvey-terraform:<ask_the_devops_team>
docker run --rm \
-v $(pwd)/config.json:/app/config.json \
-v $(pwd)/terraform-output.yaml:/app/aws/terraform-output.yaml \
-v $(pwd)/terraform-output.yaml:/app/azure/terraform-output.yaml \
-v $(pwd)/work:/app/work \
$IMAGE deploy
  • IMAGE= — Ask the DevOps team for the current tag (tags roll regularly).
  • terraform-output.yaml - Mounted at both /app/aws/... and /app/azure/..., the unified image automatically detects the cloud and uses that cloud's tree for the file. Mounting both means the active tree always reads and writes it, so deploy writes the generated terraform-output.yaml back to your host file regardless of cloud (the inactive mount is harmless). The config.json is cloud-agnostic at /app/config.json.
  • deploy - Runs terraform apply and adopt full at the same time. An apply failure aborts the process before adopt can run.

Note: The first phase of adopt full (setup-repo) generates an SSH deploy key and writes to the bind-mounted config.json (under customer_repo.deploy_key) for use by later phases.

The deploy process provisions the infrastructure and completes the ArgoCD adoption.

Option B: One Image to Each Cloud

This approach deploys one image for each cloud — the image you pick is the cloud (no automatic detection). The scripts run as separate steps instead of a single deploy. You can use this option when you want to inspect the apply before adopting, or when adopting an existing cluster. The following images are available for your cloud:

AWS_IMAGE=qrveydev.azurecr.io/qrvey-terraform-aws:<QRVEY_VERSION> AZURE_IMAGE=qrveydev.azurecr.io/qrvey-terraform-azure:<QRVEY_VERSION>

  1. Run the Terraform apply. Use the same command for a new account or when adopting an existing pre-ArgoCD cluster:

    docker run --rm \
    -v $(pwd)/config.json:/app/qrvey/config.json \
    -v $(pwd)/terraform-output.yaml:/app/qrvey/terraform-output.yaml \
    -v $(pwd)/work:/app/work \
    $AWS_IMAGE apply # Azure: $AZURE_IMAGE apply

    This command performs the following tasks:

    • Builds or updates the complete stack: VPC, EKS, RDS, IAM, Route53 + ACM, ArgoCD bootstrap, OCI registry secret, AppProjects.
    • Writes the terraform-output.yaml.

    For a fresh account, the apply builds everything from scratch. For an existing cluster, it creates only the missing pieces (ArgoCD namespace/Helm release, AppProjects, OCI registry secret, and the load balancer-controller and Route53 IAM) and applies any pending state migrations.

    A full apply is the only supported path. Avoid using a targeted (-target) apply, which cannot process the Terraform moved blocks used by an upgrade. This apply fails with moved resource instances excluded by targeting and silently skips dependencies used by the gateway and routes.

  2. Run adoption (full pipeline). The adoption scripts write intermediate artifacts (generated repository, copier answers, kong values) to /app/work/.

    Mount a local work/ directory so the artifacts persist if the pipeline fails and needs to resume. Use the same image for each cloud.

    mkdir -p work

    # Common mount flags (array works in both bash and zsh)

    MOUNT=(-v $(pwd)/config.json:/app/qrvey/config.json -v $(pwd)/terraform-output.yaml:/app/qrvey/terraform-output.yaml -v $(pwd)/work:/app/work)

    docker run --rm "${MOUNT[@]}" $AWS_IMAGE adopt full # Azure: $AZURE_IMAGE adopt full

The adopt full command runs the following processes:

  • Git repository setup.
  • Copier render of the platform-control repository.
  • Live cluster value extraction.
  • Push to Git.
  • ArgoCD bootstrap
  • Kong rip-and-replace (with DNS cutover and ACME wait).
  • Monitoring rip-and-replace.
  • Legacy Helm release secret cleanup.

Upgrade to Qrvey v9.4

To upgrade your Qrvey instance to v9.4, make the following changes to your existing config.json file:

  • Update the qrvey_chart_version variable in your config.json file to the new version.

  • Add GITOPS_ADMIN_TOKEN and GITOPS_ADMIN_EMAIL entries to your variables section.

  • Add a customer repository section:

    "customer_repo": {
    "auto_create_repo": true,
    "provider": "bitbucket",
    "org": "qrvey",
    "name": "deploytestqa405-platform-control",
    "deploy_key": ""
    }

After updating these entries, complete the installation steps using the updated qrvey_version value in the relevant commands.

This applies the upgrade and updates your environment to the specified version.

Delete a Qrvey Instance

To remove (destroy) a Qrvey instance and all associated resources, follow these steps:

  1. Navigate to the directory containing your config.json file.

  2. Run the destroy command to preview the resources that will be removed (similar to a Terraform "plan"). For example:

    docker run --platform=linux/amd64 -v $(pwd)/config.json:/app/qrvey/config.json -it --rm qrvey.azurecr.io/qrvey-terraform:${qrvey_version} destroy
  3. To remove (destroy) the instance and all associated resources, run the following command:

    docker run --platform=linux/amd64 -v $(pwd)/config.json:/app/qrvey/config.json -v $(pwd)/terraform-output.yaml:/app/aws/terraform-output.yaml -v $(pwd)/terraform-output.yaml:/app/azure/terraform-output.yaml -v $(pwd)/work:/app/work -it --rm qrveydev.azurecr.io/qrvey-terraform:9.4-20260714-3306 destroy

Warning: When the resources are removed, all data and metadata associated with the instance is permanently deleted and cannot be recovered.

Additional Resources