Skip to main content

Provisioning ACK Resources

By default the Carts component in the sample application uses a DynamoDB local instance running as a pod in the EKS cluster called carts-dynamodb. In this section of the lab, we'll provision an Amazon DynamoDB cloud based table for our application using Kubernetes custom resources and point the Carts deployment to use the newly provisioned DynamoDB table instead of the local copy.

ACK reconciler concept

The AWS Java SDK in the Carts component is able to use IAM Roles to interact with AWS services which means that we do not need to pass credentials, thus reducing the attack surface. In the EKS context, IRSA allows us to define per pod IAM Roles for applications to consume. To leverage IRSA, we first need to:

  • Create a Kubernetes Service Account in the Carts namespace
  • Create an IAM Policy with necessary DynamoDB permissions
  • Create an IAM Role in AWS with the above permissions
  • Map the Service Account to use the IAM role using Annotations in the Service Account definition.

Fortunately, we have a handy one-liner to help with this process. Run the below:

~$eksctl create iamserviceaccount --name carts-ack \
--namespace carts --cluster $EKS_CLUSTER_NAME \
--role-name ${EKS_CLUSTER_NAME}-carts-ack \
--attach-policy-arn $DYNAMODB_POLICY_ARN --approve
2023-10-31 16:20:46 [i]  1 iamserviceaccount (carts/carts-ack) was included (based on the include/exclude rules)
2023-10-31 16:20:46 [i]  1 task: {
    2 sequential sub-tasks: {
        create IAM role for serviceaccount "carts/carts-ack",
        create serviceaccount "carts/carts-ack",
    } }2023-10-31 16:20:46 [ℹ]  building iamserviceaccount stack "eksctl-eks-workshop-addon-iamserviceaccount-carts-carts-ack"
2023-10-31 16:20:46 [i]  deploying stack "eksctl-eks-workshop-addon-iamserviceaccount-carts-carts-ack"
2023-10-31 16:20:47 [i]  waiting for CloudFormation stack "eksctl-eks-workshop-addon-iamserviceaccount-carts-carts-ack"
2023-10-31 16:21:17 [i]  waiting for CloudFormation stack "eksctl-eks-workshop-addon-iamserviceaccount-carts-carts-ack"
2023-10-31 16:21:17 [i]  created serviceaccount "carts/carts-ack"

eksctl provisions a CloudFormation stack to help manage these resources which can be seen in the output above.

To learn more about how IRSA works, go here.


Now, let's explore how we'll create the DynamoDB Table via a Kubernetes manifest

~/environment/eks-workshop/modules/automation/controlplanes/ack/dynamodb/dynamodb-create.yaml
apiVersion: dynamodb.services.k8s.aws/v1alpha1
kind: Table
metadata:
name: items
namespace: carts
spec:
keySchema:
- attributeName: id
keyType: HASH
attributeDefinitions:
- attributeName: id
attributeType: 'S'
- attributeName: customerId
attributeType: 'S'
billingMode: PAY_PER_REQUEST
tableName: "${EKS_CLUSTER_NAME}-carts-ack"
globalSecondaryIndexes:
- indexName: idx_global_customerId
keySchema:
- attributeName: customerId
keyType: HASH
- attributeName: id
keyType: RANGE
projection:
projectionType: 'ALL'
info

Astute readers will notice the YAML Spec to be similar to the API endpoints and calls for DynamoDB such as tableName and attributeDefinitions.

Next, we will need to update the regional endpoint for DynamoDB within the Configmap used by the Kustomization to update the Carts deployment.

~/environment/eks-workshop/modules/automation/controlplanes/ack/dynamodb/dynamodb-ack-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: carts-ack
namespace: carts
data:
CARTS_DYNAMODB_TABLENAME: "${EKS_CLUSTER_NAME}-carts-ack"
CARTS_DYNAMODB_ENDPOINT: https://dynamodb.${AWS_REGION}.amazonaws.com

Using the envsubst utility, we will rewrite the environment variable AWS_REGION into the manifest and apply all the updates to the cluster. Run the below

~$kubectl kustomize ~/environment/eks-workshop/modules/automation/controlplanes/ack/dynamodb \
| envsubst | kubectl apply -f-
namespace/carts unchanged
serviceaccount/carts unchanged
configmap/carts unchanged
configmap/carts-ack created
service/carts unchanged
service/carts-dynamodb unchanged
deployment.apps/carts configured
deployment.apps/carts-dynamodb unchanged
table.dynamodb.services.k8s.aws/items created
~$kubectl rollout status -n carts deployment/carts --timeout=120s
info

This command 'builds' the manifests using the kubectl kustomize command, pipes it to envsubst and then to kubectl apply. This makes it easy to template manifests and populate them at run-time.

The ACK controllers in the cluster will react to these new resources and provision the AWS infrastructure we have expressed with the manifests earlier. Lets check if ACK created the table by running

~$kubectl wait table.dynamodb.services.k8s.aws items -n carts --for=condition=ACK.ResourceSynced --timeout=15m
table.dynamodb.services.k8s.aws/items condition met
~$kubectl get table.dynamodb.services.k8s.aws items -n carts -ojson | yq '.status."tableStatus"'
ACTIVE

And now to check if the Table has been created using the AWS CLI, run

~$aws dynamodb list-tables
{
    "TableNames": [
        "eks-workshop-carts-ack"
    ]
}

This output tells us that the new table has been created!