Skip to main content
The aws.ecr.enable_pull_through_cache advanced setting caches the public ECR images of Qovery-managed infrastructure components in the private ECR registry of your AWS account. Its goal is to cut the NAT Gateway charges generated when nodes pull these images. On a VPC managed by Qovery, Qovery creates the VPC endpoints that keep these pulls inside the VPC. When the cluster runs on your existing VPC, you own the network, so you create these endpoints yourself. This tutorial walks through the setup with the AWS CLI.

How it works

Nodes reach the private ECR registry through two interface endpoints, and download image layers from Amazon S3 through a gateway endpoint. On the first pull of an image, Amazon ECR imports it from public.ecr.aws itself, without going through your NAT Gateway. You need: Without the S3 gateway endpoint, image layers, which make up most of the traffic, still go through the NAT Gateway.
The S3 gateway endpoint has no charge. Interface endpoints are billed per hour and per availability zone, plus a charge per GB processed that is lower than the NAT Gateway one. See AWS PrivateLink pricing.

Prerequisites

  • A Qovery-managed EKS cluster deployed on your existing VPC, with Karpenter enabled
  • AWS CLI v2 with credentials allowed to manage VPC endpoints, security groups and VPC attributes in the cluster’s AWS account
  • The VPC ID and the subnet IDs you entered when creating the cluster
The node subnets are the EKS subnets of the cluster, plus its private subnets when nodes are created in private subnets. The endpoints must be in the cluster VPC itself: Qovery does not look for endpoints shared from another VPC.

Step 1: Set the variables

The commands of this tutorial work in bash and zsh. Replace the values with yours:
An interface endpoint accepts only one subnet per availability zone. The node subnets themselves can host it.

Step 2: Check the existing endpoints

If an endpoint already exists for a service, do not create a second one: the steps below explain how to update it.

Step 3: Enable DNS in the VPC

Private DNS on interface endpoints requires both DNS attributes of the VPC. The command changes one attribute at a time:

Step 4: Create the security group of the ECR endpoints

Create a security group that accepts TCP 443 from every CIDR block of the VPC, which covers all node subnets. The commands reuse the group if it already exists, so you can run them again:
Check that the echo prints a security group ID (sg-...) before going further: the next steps use it. When you run the commands again, authorize-security-group-ingress reports InvalidPermission.Duplicate for the rules that already exist. You can ignore it. Qovery accepts any of these sources on the endpoint security groups:
  • A CIDR that contains each node subnet, such as the VPC CIDR or the subnet CIDRs
  • The EKS cluster security group, which exists only after the first cluster deployment
  • A prefix list. Qovery does not resolve it and trusts that it covers the node subnets
Create this security group before enabling private DNS on the endpoints. With private DNS, every ECR request made from the VPC goes through the endpoint, including the pulls of your own applications. If the endpoint security group blocks TCP 443, every ECR pull in the VPC fails.

Step 5: Create the ECR interface endpoints

If an ECR endpoint already exists, update it instead of creating a second one. Run the following for each existing ECR endpoint. First, add the security group and enable private DNS:
Then check that the endpoint has a subnet in every availability zone where nodes run. Compare the zones it covers with the zones of your endpoint subnets:
For each zone missing from the endpoint, add the matching subnet. An endpoint accepts only one subnet per zone, so do not add subnets for the zones it already covers:
Nodes in a zone without an endpoint subnet still reach the endpoint through another zone, so Qovery does not report it. That traffic adds cross-zone data transfer charges and depends on the other zone being available. The endpoints become available after a few minutes. Run the command of step 2 to follow their state.

Step 6: Find the route tables of the node subnets

A subnet without an explicit route table association uses the main route table of the VPC:

Step 7: Attach an S3 gateway endpoint to these route tables

If an S3 gateway endpoint already exists, attach the route tables to it instead:

Step 8: Review what Qovery does not check

Qovery checks the endpoints, their private DNS, their security groups and the route tables. It does not check the following, which can still block image pulls:
  • Endpoint policies: keep the default policy, which allows full access. A restricted policy on the ECR endpoints must allow pulling images and, for the cache, ecr:BatchImportUpstreamImage and ecr:CreateRepository on arn:aws:ecr:<region>:<account-id>:repository/qovery-ecr-public/*. A restricted policy on the S3 endpoint must allow s3:GetObject on arn:aws:s3:::prod-<region>-starport-layer-bucket/*, the bucket that serves ECR image layers. See Amazon ECR interface VPC endpoints.
  • Network ACLs: custom network ACLs on the node and endpoint subnets must allow TCP 443 from the nodes to the endpoint subnets and to Amazon S3, and the return traffic on ephemeral ports (1024-65535).

Step 9: Enable the setting and deploy the cluster

Set aws.ecr.enable_pull_through_cache to true in the advanced settings of the cluster, then deploy the cluster. During the deployment, Qovery checks the endpoints. When everything is in place, the cluster logs show:
If something is missing, the deployment goes through every step and then ends in error, listing what is missing. Qovery components still use the cache, but their traffic goes through the NAT Gateway until you fix the VPC and deploy the cluster again.

Troubleshooting

The deployment error lists one entry per missing prerequisite: If the error says that Qovery cannot check the custom VPC, the AWS credentials of the cluster are missing one of these permissions: ec2:DescribeVpcEndpoints, ec2:DescribeSubnets, ec2:DescribeRouteTables, ec2:DescribeSecurityGroups.