IK.AM


Dev > CaaS > Kubernetes > TAP

Tanzu Application Platform 1.7 (Full Profile) をEKSにインストールするメモ

Created on Tue Dec 12 2023 • Last Updated on Mon Jan 15 2024N/A Views

🏷️ Kubernetes | Cartographer | EKS | ECR | Tanzu | TAP

目次

EKSクラスタの作成

brew install awscli
brew install eksctl
export AWS_ACCESS_KEY_ID=*****
export AWS_SECRET_ACCESS_KEY=*****
export AWS_SESSION_TOKEN=****
cat <<EOF > eks-cluster-config.yaml
---
kind: ClusterConfig
apiVersion: eksctl.io/v1alpha5
metadata:
  name: tap-eks
  region: ap-northeast-1
  version: "1.28"
managedNodeGroups:
- name: tap-eks-ng-1
  minSize: 3
  maxSize: 3
  desiredCapacity: 3
  volumeSize: 200
  maxPodsPerNode: 110
  instanceType: m5.xlarge
  spot: false # <--- If you want to use spot instances, set true. If you intend to use sslip.io for the shared.ingress_domain below, I recommend avoiding the use of spot instances.
  ssh:
    allow: true
    publicKeyPath: ~/.ssh/id_rsa.pub
addons:
- name: aws-ebs-csi-driver
  wellKnownPolicies:
    ebsCSIController: true
iam:
  withOIDC: true
---
EOF
eksctl create cluster -f eks-cluster-config.yaml
$ kubectl get node -owide
NAME                                                STATUS   ROLES    AGE     VERSION               INTERNAL-IP      EXTERNAL-IP      OS-IMAGE         KERNEL-VERSION                  CONTAINER-RUNTIME
ip-192-168-19-134.ap-northeast-1.compute.internal   Ready    <none>   5m31s   v1.28.3-eks-e71965b   192.168.19.134   35.78.100.84     Amazon Linux 2   5.10.199-190.747.amzn2.x86_64   containerd://1.7.3
ip-192-168-39-153.ap-northeast-1.compute.internal   Ready    <none>   5m32s   v1.28.3-eks-e71965b   192.168.39.153   54.199.122.212   Amazon Linux 2   5.10.199-190.747.amzn2.x86_64   containerd://1.7.3
ip-192-168-79-97.ap-northeast-1.compute.internal    Ready    <none>   5m31s   v1.28.3-eks-e71965b   192.168.79.97    43.207.126.145   Amazon Linux 2   5.10.199-190.747.amzn2.x86_64   containerd://1.7.3
$ kubectl get nodes -o=custom-columns='NAME:.metadata.name,INSTANCE-TYPE:.metadata.labels.beta\.kubernetes\.io/instance-type,CAPACITY-TYPE:.metadata.labels.eks\.amazonaws\.com/capacityType,ZONE:.metadata.labels.failure-domain\.beta\.kubernetes\.io/zone'
NAME                                                INSTANCE-TYPE   CAPACITY-TYPE   ZONE
ip-192-168-19-134.ap-northeast-1.compute.internal   m5.xlarge       ON_DEMAND       ap-northeast-1c
ip-192-168-39-153.ap-northeast-1.compute.internal   m5.xlarge       ON_DEMAND       ap-northeast-1a
ip-192-168-79-97.ap-northeast-1.compute.internal    m5.xlarge       ON_DEMAND       ap-northeast-1d

ECRレポジトリの作成

export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
export AWS_REGION=ap-northeast-1
export EKS_CLUSTER_NAME=tap-eks
aws ecr create-repository --repository-name tap-images --region $AWS_REGION
aws ecr create-repository --repository-name tap-build-service --region $AWS_REGION

aws ecr create-repository --repository-name full-deps-package-repo --region $AWS_REGION
aws ecr create-repository --repository-name tap-lsp --region $AWS_REGION
aws ecr create-repository --repository-name tanzu-cluster-essentials --region $AWS_REGION

IAMロールの作成

# Retrieve the OIDC endpoint from the Kubernetes cluster and store it for use in the policy.
export OIDCPROVIDER=$(aws eks describe-cluster --name $EKS_CLUSTER_NAME --region $AWS_REGION --output json | jq '.cluster.identity.oidc.issuer' | tr -d '"' | sed 's/https:\/\///')
cat << EOF > build-service-trust-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDCPROVIDER}"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "${OIDCPROVIDER}:aud": "sts.amazonaws.com"
                },
                "StringLike": {
                    "${OIDCPROVIDER}:sub": [
                        "system:serviceaccount:kpack:controller",
                        "system:serviceaccount:build-service:dependency-updater-controller-serviceaccount"
                    ]
                }
            }
        }
    ]
}
EOF

cat << EOF > build-service-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "ecr:DescribeRegistry",
                "ecr:GetAuthorizationToken",
                "ecr:GetRegistryPolicy",
                "ecr:PutRegistryPolicy",
                "ecr:PutReplicationConfiguration",
                "ecr:DeleteRegistryPolicy"
            ],
            "Resource": "*",
            "Effect": "Allow",
            "Sid": "TAPEcrBuildServiceGlobal"
        },
        {
            "Action": [
                "ecr:DescribeImages",
                "ecr:ListImages",
                "ecr:BatchCheckLayerAvailability",
                "ecr:BatchGetImage",
                "ecr:BatchGetRepositoryScanningConfiguration",
                "ecr:DescribeImageReplicationStatus",
                "ecr:DescribeImageScanFindings",
                "ecr:DescribeRepositories",
                "ecr:GetDownloadUrlForLayer",
                "ecr:GetLifecyclePolicy",
                "ecr:GetLifecyclePolicyPreview",
                "ecr:GetRegistryScanningConfiguration",
                "ecr:GetRepositoryPolicy",
                "ecr:ListTagsForResource",
                "ecr:TagResource",
                "ecr:UntagResource",
                "ecr:BatchDeleteImage",
                "ecr:BatchImportUpstreamImage",
                "ecr:CompleteLayerUpload",
                "ecr:CreatePullThroughCacheRule",
                "ecr:CreateRepository",
                "ecr:DeleteLifecyclePolicy",
                "ecr:DeletePullThroughCacheRule",
                "ecr:DeleteRepository",
                "ecr:InitiateLayerUpload",
                "ecr:PutImage",
                "ecr:PutImageScanningConfiguration",
                "ecr:PutImageTagMutability",
                "ecr:PutLifecyclePolicy",
                "ecr:PutRegistryScanningConfiguration",
                "ecr:ReplicateImage",
                "ecr:StartImageScan",
                "ecr:StartLifecyclePolicyPreview",
                "ecr:UploadLayerPart",
                "ecr:DeleteRepositoryPolicy",
                "ecr:SetRepositoryPolicy"
            ],
            "Resource": [
                "arn:aws:ecr:${AWS_REGION}:${AWS_ACCOUNT_ID}:repository/full-deps-package-repo",
                "arn:aws:ecr:${AWS_REGION}:${AWS_ACCOUNT_ID}:repository/tap-build-service",
                "arn:aws:ecr:${AWS_REGION}:${AWS_ACCOUNT_ID}:repository/tap-images"
            ],
            "Effect": "Allow",
            "Sid": "TAPEcrBuildServiceScoped"
        }
    ]
}
EOF

cat << EOF > workload-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "ecr:DescribeRegistry",
                "ecr:GetAuthorizationToken",
                "ecr:GetRegistryPolicy",
                "ecr:PutRegistryPolicy",
                "ecr:PutReplicationConfiguration",
                "ecr:DeleteRegistryPolicy"
            ],
            "Resource": "*",
            "Effect": "Allow",
            "Sid": "TAPEcrWorkloadGlobal"
        },
        {
            "Action": [
                "ecr:DescribeImages",
                "ecr:ListImages",
                "ecr:BatchCheckLayerAvailability",
                "ecr:BatchGetImage",
                "ecr:BatchGetRepositoryScanningConfiguration",
                "ecr:DescribeImageReplicationStatus",
                "ecr:DescribeImageScanFindings",
                "ecr:DescribeRepositories",
                "ecr:GetDownloadUrlForLayer",
                "ecr:GetLifecyclePolicy",
                "ecr:GetLifecyclePolicyPreview",
                "ecr:GetRegistryScanningConfiguration",
                "ecr:GetRepositoryPolicy",
                "ecr:ListTagsForResource",
                "ecr:TagResource",
                "ecr:UntagResource",
                "ecr:BatchDeleteImage",
                "ecr:BatchImportUpstreamImage",
                "ecr:CompleteLayerUpload",
                "ecr:CreatePullThroughCacheRule",
                "ecr:CreateRepository",
                "ecr:DeleteLifecyclePolicy",
                "ecr:DeletePullThroughCacheRule",
                "ecr:DeleteRepository",
                "ecr:InitiateLayerUpload",
                "ecr:PutImage",
                "ecr:PutImageScanningConfiguration",
                "ecr:PutImageTagMutability",
                "ecr:PutLifecyclePolicy",
                "ecr:PutRegistryScanningConfiguration",
                "ecr:ReplicateImage",
                "ecr:StartImageScan",
                "ecr:StartLifecyclePolicyPreview",
                "ecr:UploadLayerPart",
                "ecr:DeleteRepositoryPolicy",
                "ecr:SetRepositoryPolicy"
            ],
            "Resource": [
                "arn:aws:ecr:${AWS_REGION}:${AWS_ACCOUNT_ID}:repository/full-deps-package-repo",
                "arn:aws:ecr:${AWS_REGION}:${AWS_ACCOUNT_ID}:repository/tanzu-application-platform/*"
            ],
            "Effect": "Allow",
            "Sid": "TAPEcrWorkloadScoped"
        }
    ]
}
EOF

cat << EOF > workload-trust-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDCPROVIDER}"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringLike": {
                    "${OIDCPROVIDER}:sub": "system:serviceaccount:*:default",
                    "${OIDCPROVIDER}:aud": "sts.amazonaws.com"
                }
            }
        }
    ]
}
EOF

cat << EOF > local-source-proxy-trust-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDCPROVIDER}"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "${OIDCPROVIDER}:aud": "sts.amazonaws.com"
                },
                "StringLike": {
                    "${OIDCPROVIDER}:sub": [
                        "system:serviceaccount:tap-local-source-system:proxy-manager"
                    ]
                }
            }
        }
    ]
}
EOF

cat << EOF > local-source-proxy-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "ecr:GetAuthorizationToken"
            ],
            "Resource": "*",
            "Effect": "Allow",
            "Sid": "TAPLSPGlobal"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ecr:BatchCheckLayerAvailability",
                "ecr:GetDownloadUrlForLayer",
                "ecr:GetRepositoryPolicy",
                "ecr:DescribeRepositories",
                "ecr:ListImages",
                "ecr:DescribeImages",
                "ecr:BatchGetImage",
                "ecr:GetLifecyclePolicy",
                "ecr:GetLifecyclePolicyPreview",
                "ecr:ListTagsForResource",
                "ecr:DescribeImageScanFindings",
                "ecr:InitiateLayerUpload",
                "ecr:UploadLayerPart",
                "ecr:CompleteLayerUpload",
                "ecr:PutImage"
            ],
            "Resource": [
                "arn:aws:ecr:${AWS_REGION}:${AWS_ACCOUNT_ID}:repository/tap-lsp"
            ],
            "Sid": "TAPLSPScoped"
        }
    ]
}
EOF

aws iam create-role --role-name tap-build-service --assume-role-policy-document file://build-service-trust-policy.json
aws iam put-role-policy --role-name tap-build-service --policy-name tapBuildServicePolicy --policy-document file://build-service-policy.json

aws iam create-role --role-name tap-workload --assume-role-policy-document file://workload-trust-policy.json
aws iam put-role-policy --role-name tap-workload --policy-name tapWorkload --policy-document file://workload-policy.json

aws iam create-role --role-name tap-local-source-proxy --assume-role-policy-document file://local-source-proxy-trust-policy.json
aws iam put-role-policy --role-name tap-local-source-proxy --policy-name tapLocalSourcePolicy --policy-document file://local-source-proxy-policy.json

Cluster Essentialsのインストール

IMGPKG_REGISTRY_HOSTNAME=registry.tanzu.vmware.com \
IMGPKG_REGISTRY_USERNAME=$TANZUNET_USERNAME \
IMGPKG_REGISTRY_PASSWORD=$TANZUNET_PASSWORD \
imgpkg copy \
  -b registry.tanzu.vmware.com/tanzu-cluster-essentials/cluster-essentials-bundle:1.7.2 \
  --to-tar cluster-essentials-bundle-1.7.2.tar \
  --include-non-distributable-layers
ECR_REPO=$(aws ecr describe-repositories --region ap-northeast-1 --query 'repositories[?repositoryName==`tanzu-cluster-essentials`].repositoryUri' --output text)
aws ecr get-login-password --region ${AWS_REGION} | docker login ${ECR_REPO} -u AWS --password-stdin

imgpkg copy \
  --tar cluster-essentials-bundle-1.7.2.tar \
  --to-repo ${ECR_REPO} \
  --include-non-distributable-layers
pivnet download-product-files --product-slug='tanzu-cluster-essentials' --release-version='1.7.2' --glob='tanzu-cluster-essentials-darwin-amd64-*'

mkdir -p tanzu-cluster-essentials
tar -xvf tanzu-cluster-essentials-*.tgz -C tanzu-cluster-essentials
cd tanzu-cluster-essentials

INSTALL_BUNDLE=${ECR_REPO}:1.7.2 \
INSTALL_REGISTRY_HOSTNAME=dummy.example.com \
INSTALL_REGISTRY_USERNAME=dummy \
INSTALL_REGISTRY_PASSWORD=dummy \
./install.sh --yes
cd ..

Tanzu Application Platformのインストール

IMGPKG_REGISTRY_HOSTNAME=registry.tanzu.vmware.com \
IMGPKG_REGISTRY_USERNAME=$TANZUNET_USERNAME \
IMGPKG_REGISTRY_PASSWORD=$TANZUNET_PASSWORD \
imgpkg copy \
  -b registry.tanzu.vmware.com/tanzu-application-platform/tap-packages:1.7.3 \
  --to-tar tap-bundle-1.7.3.tar \
  --include-non-distributable-layers
ECR_REPO=$(aws ecr describe-repositories --region ap-northeast-1 --query 'repositories[?repositoryName==`tap-images`].repositoryUri' --output text)
aws ecr get-login-password --region ${AWS_REGION} | docker login ${ECR_REPO} -u AWS --password-stdin

imgpkg copy \
  --concurrency 1 \
  --tar tap-bundle-1.7.3.tar \
  --to-repo ${ECR_REPO} \
  --include-non-distributable-layers
brew install vmware-tanzu/tanzu/tanzu-cli
tanzu plugin install --group vmware-tap/default:v1.7.3
kubectl create ns tap-install
tanzu package repository add tanzu-tap-repository \
  --url ${ECR_REPO}:1.7.3 \
  --namespace tap-install
aws ec2 allocate-address --region ${AWS_REGION} > envoy-eip-1.json
aws ec2 create-tags --resources $(cat envoy-eip-1.json | jq -r .AllocationId) --region ${AWS_REGION} --tags Key=Name,Value=envoy-ip-1

aws ec2 allocate-address --region ${AWS_REGION} > envoy-eip-2.json
aws ec2 create-tags --resources $(cat envoy-eip-2.json | jq -r .AllocationId) --region ${AWS_REGION} --tags Key=Name,Value=envoy-ip-2

aws ec2 allocate-address --region ${AWS_REGION} > envoy-eip-3.json
aws ec2 create-tags --resources $(cat envoy-eip-3.json | jq -r .AllocationId) --region ${AWS_REGION} --tags Key=Name,Value=envoy-ip-3
cat << EOF > tap-values.yaml
---
shared:
  ingress_domain: tap.$(cat envoy-eip-1.json | jq -r .PublicIp).sslip.io

ceip_policy_disclosed: true

profile: full

supply_chain: testing_scanning

ootb_supply_chain_testing_scanning:
  registry:
    server: ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com
    # The prefix of the ECR repository.  Workloads will need
    # two repositories created:
    #
    # tanzu-application-platform/<workloadname>-<namespace>
    # tanzu-application-platform/<workloadname>-<namespace>-bundle
    repository: tanzu-application-platform

contour:
  infrastructure_provider: aws
  envoy:
    workload:
      type: Deployment
      replicas: 2
    service:
      type: LoadBalancer
      annotations: 
        service.beta.kubernetes.io/aws-load-balancer-eip-allocations: $(cat envoy-eip-1.json | jq -r .AllocationId),$(cat envoy-eip-2.json | jq -r .AllocationId),$(cat envoy-eip-3.json | jq -r .AllocationId)
      aws:
        LBType: nlb
  contour:
    replicas: 1
    configFileContents:
      accesslog-format: json

buildservice:
  kp_default_repository: ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/tap-build-service
  kp_default_repository_aws_iam_role_arn: arn:aws:iam::${AWS_ACCOUNT_ID}:role/tap-build-service
  exclude_dependencies: true

local_source_proxy:
  repository: ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/tap-lsp
  push_secret:
    aws_iam_role_arn: arn:aws:iam::${AWS_ACCOUNT_ID}:role/tap-local-source-proxy

ootb_templates:
  iaas_auth: true

springboot_conventions:
  autoConfigureActuators: true

tap_gui:
  app_config:
    auth:
      allowGuestAccess: true
    customize:
      features:
        supplyChain:
          enableTriageUI: true

metadata_store:
  ns_for_export_app_cert: "*"
  app_service_type: ClusterIP
  pg_req_cpu: "200m"
  pg_req_memory: "200Mi"

namespace_provisioner:
  aws_iam_role_arn: arn:aws:iam::${AWS_ACCOUNT_ID}:role/tap-workload

cnrs:
  allow_manual_configmap_update: false
  # 以下リソース節約用
  lite:
    enable: true
  pdb:
    enable: false
cartographer:
  cartographer:
    resources:
      requests:
        cpu: 100m
        memory: 200Mi
crossplane:
  resourcesCrossplane:
    requests:
      cpu: 100m
      memory: 200Mi
  resourcesRBACManager:
    requests:
      cpu: 100m
      memory: 200Mi

excluded_packages:
- policy.apps.tanzu.vmware.com
- sso.apps.tanzu.vmware.com
- api-portal.tanzu.vmware.com
EOF
tanzu package install tap -p tap.tanzu.vmware.com -v 1.7.3 --values-file tap-values.yaml -n tap-install
IMGPKG_REGISTRY_HOSTNAME=registry.tanzu.vmware.com \
IMGPKG_REGISTRY_USERNAME=$TANZUNET_USERNAME \
IMGPKG_REGISTRY_PASSWORD=$TANZUNET_PASSWORD \
imgpkg copy \
  -b registry.tanzu.vmware.com/tanzu-application-platform/full-deps-package-repo:1.7.3 \
  --to-tar full-deps-1.7.3.tar \
  --include-non-distributable-layers


ECR_REPO=$(aws ecr describe-repositories --region ap-northeast-1 --query 'repositories[?repositoryName==`full-deps-package-repo`].repositoryUri' --output text)
aws ecr get-login-password --region ap-northeast-1 | docker login ${ECR_REPO} -u AWS --password-stdin

imgpkg copy \
  --tar full-deps-1.7.3.tar \
  --to-repo ${ECR_REPO} \
  --include-non-distributable-layers
tanzu package repository add full-deps-package-repo \
  --url ${ECR_REPO}:1.7.3 \
  --namespace tap-install
tanzu package install full-deps -p full-deps.buildservice.tanzu.vmware.com -v "> 0.0.0" -n tap-install --values-file tap-values.yaml
$ kubectl get pkgi -n tap-install
NAME                                 PACKAGE NAME                                          PACKAGE VERSION   DESCRIPTION           AGE
accelerator                          accelerator.apps.tanzu.vmware.com                     1.7.7             Reconcile succeeded   36m
amr-observer                         amr-observer.apps.tanzu.vmware.com                    0.2.1             Reconcile succeeded   36m
api-auto-registration                apis.apps.tanzu.vmware.com                            0.4.2             Reconcile succeeded   36m
appliveview                          backend.appliveview.tanzu.vmware.com                  1.7.3             Reconcile succeeded   36m
appliveview-apiserver                apiserver.appliveview.tanzu.vmware.com                1.7.3             Reconcile succeeded   37m
appliveview-connector                connector.appliveview.tanzu.vmware.com                1.7.3             Reconcile succeeded   38m
appliveview-conventions              conventions.appliveview.tanzu.vmware.com              1.7.3             Reconcile succeeded   37m
base-jammy-builder                   base-jammy-builder.buildpacks.tanzu.vmware.com        0.1.0             Reconcile succeeded   2m8s
base-jammy-stack                     base-jammy-stack.buildpacks.tanzu.vmware.com          0.1.74            Reconcile succeeded   2m26s
bitnami-services                     bitnami.services.tanzu.vmware.com                     0.3.1             Reconcile succeeded   37m
buildservice                         buildservice.tanzu.vmware.com                         1.12.4            Reconcile succeeded   38m
cartographer                         cartographer.tanzu.vmware.com                         0.8.5             Reconcile succeeded   37m
cert-manager                         cert-manager.tanzu.vmware.com                         2.4.2             Reconcile succeeded   38m
cnrs                                 cnrs.tanzu.vmware.com                                 2.4.3             Reconcile succeeded   36m
contour                              contour.tanzu.vmware.com                              1.25.3            Reconcile succeeded   37m
crossplane                           crossplane.tanzu.vmware.com                           0.3.0             Reconcile succeeded   38m
developer-conventions                developer-conventions.tanzu.vmware.com                0.14.2            Reconcile succeeded   37m
dotnet-core-buildpack                dotnet-core.buildpacks.tanzu.vmware.com               2.8.3             Reconcile succeeded   2m26s
fluxcd-source-controller             fluxcd.source.controller.tanzu.vmware.com             0.36.1+tanzu.2    Reconcile succeeded   38m
full-deps                            full-deps.buildservice.tanzu.vmware.com               1.7.55            Reconcile succeeded   2m28s
full-jammy-builder                   full-jammy-builder.buildpacks.tanzu.vmware.com        0.1.0             Reconcile succeeded   2m8s
full-jammy-stack                     full-jammy-stack.buildpacks.tanzu.vmware.com          0.1.129           Reconcile succeeded   2m26s
go-buildpack                         go.buildpacks.tanzu.vmware.com                        2.2.3             Reconcile succeeded   2m26s
java-buildpack                       java.buildpacks.tanzu.vmware.com                      9.12.2            Reconcile succeeded   2m26s
java-native-image-buildpack          java-native-image.buildpacks.tanzu.vmware.com         7.10.1            Reconcile succeeded   2m26s
local-source-proxy                   local-source-proxy.apps.tanzu.vmware.com              0.2.1             Reconcile succeeded   38m
metadata-store                       metadata-store.apps.tanzu.vmware.com                  1.7.2             Reconcile succeeded   36m
namespace-provisioner                namespace-provisioner.apps.tanzu.vmware.com           0.5.0             Reconcile succeeded   37m
nodejs-buildpack                     nodejs.buildpacks.tanzu.vmware.com                    2.3.3             Reconcile succeeded   2m26s
ootb-delivery-basic                  ootb-delivery-basic.tanzu.vmware.com                  0.14.10           Reconcile succeeded   37m
ootb-supply-chain-testing-scanning   ootb-supply-chain-testing-scanning.tanzu.vmware.com   0.14.10           Reconcile succeeded   37m
ootb-templates                       ootb-templates.tanzu.vmware.com                       0.14.10           Reconcile succeeded   37m
php-buildpack                        php.buildpacks.tanzu.vmware.com                       2.6.2             Reconcile succeeded   2m26s
procfile-buildpack                   procfile.buildpacks.tanzu.vmware.com                  5.6.1             Reconcile succeeded   2m26s
python-buildpack                     python.buildpacks.tanzu.vmware.com                    2.5.3             Reconcile succeeded   2m26s
ruby-buildpack                       ruby.buildpacks.tanzu.vmware.com                      2.8.2             Reconcile succeeded   2m26s
scanning                             scanning.apps.tanzu.vmware.com                        1.7.3             Reconcile succeeded   37m
service-bindings                     servicebinding.tanzu.vmware.com                       0.10.3            Reconcile succeeded   37m
services-toolkit                     services-toolkit.tanzu.vmware.com                     0.12.0            Reconcile succeeded   37m
source-controller                    controller.source.apps.tanzu.vmware.com               0.8.3             Reconcile succeeded   37m
spring-boot-conventions              spring-boot-conventions.tanzu.vmware.com              1.7.3             Reconcile succeeded   37m
tap                                  tap.tanzu.vmware.com                                  1.7.3             Reconcile succeeded   38m
tap-auth                             tap-auth.tanzu.vmware.com                             1.1.0             Reconcile succeeded   38m
tap-gui                              tap-gui.tanzu.vmware.com                              1.7.9             Reconcile succeeded   36m
tap-telemetry                        tap-telemetry.tanzu.vmware.com                        0.7.0             Reconcile succeeded   38m
tekton-pipelines                     tekton.tanzu.vmware.com                               0.50.3+tanzu.3    Reconcile succeeded   38m
tiny-jammy-builder                   tiny-jammy-builder.buildpacks.tanzu.vmware.com        0.1.0             Reconcile succeeded   2m8s
tiny-jammy-stack                     tiny-jammy-stack.buildpacks.tanzu.vmware.com          0.1.78            Reconcile succeeded   2m26s
web-servers-buildpack                web-servers.buildpacks.tanzu.vmware.com               0.15.5            Reconcile succeeded   2m26s
$ kubectl get svc -n tanzu-system-ingress envoy
NAME    TYPE           CLUSTER-IP       EXTERNAL-IP                                                                          PORT(S)                      AGE
envoy   LoadBalancer   10.100.187.245   a6a44a1ab9fe14882b6a8cb90ae0b970-c12e1d630e8c3500.elb.ap-northeast-1.amazonaws.com   80:31413/TCP,443:31473/TCP   37m
$ kubectl get svc -n tanzu-system-ingress envoy -ojsonpath='{.status.loadBalancer.ingress[0].hostname}'
a6a44a1ab9fe14882b6a8cb90ae0b970-c12e1d630e8c3500.elb.ap-northeast-1.amazonaws.com
$ kubectl get httpproxy -A
NAMESPACE               NAME                               FQDN                                                TLS SECRET                            STATUS   STATUS DESCRIPTION
api-auto-registration   api-auto-registration-controller   api-auto-registration.tap.52.69.252.111.sslip.io    api-auto-registration-cert            valid    Valid HTTPProxy
metadata-store          amr-cloudevent-handler-ingress     amr-cloudevent-handler.tap.52.69.252.111.sslip.io   amr-cloudevent-handler-ingress-cert   valid    Valid HTTPProxy
metadata-store          amr-graphql-ingress                amr-graphql.tap.52.69.252.111.sslip.io              amr-ingress-cert                      valid    Valid HTTPProxy
metadata-store          metadata-store-ingress             metadata-store.tap.52.69.252.111.sslip.io           ingress-cert                          valid    Valid HTTPProxy
tap-gui                 tap-gui                            tap-gui.tap.52.69.252.111.sslip.io                  tap-gui-cert                          valid    Valid HTTPProxy

https://tap-gui.tap.52.69.252.111.sslip.io

image
$ kubectl get clusterbuilder 
NAME         LATESTIMAGE                                                                                                                                                      READY
base-jammy   198656008139.dkr.ecr.ap-northeast-1.amazonaws.com/tap-build-service:base-jammy-builder@sha256:2b602d503b56d18a67058f988344b2b0327986422ab1f864520f71e88c1265cb   True
default      198656008139.dkr.ecr.ap-northeast-1.amazonaws.com/tap-build-service:default-builder@sha256:2b602d503b56d18a67058f988344b2b0327986422ab1f864520f71e88c1265cb      True
full-jammy   198656008139.dkr.ecr.ap-northeast-1.amazonaws.com/tap-build-service:full-jammy-builder@sha256:c6031fa62b72108558c679121ab51b40b903a722001a353fc0b257d91042f38d   True
tiny-jammy   198656008139.dkr.ecr.ap-northeast-1.amazonaws.com/tap-build-service:tiny-jammy-builder@sha256:befbf884e0ffe27fbd28da8757b7fc3a343027a47e5073b691d48586993e2ee2   True

Workloadの作成

kubectl create ns demo
kubectl label namespaces demo apps.tanzu.vmware.com/tap-ns=""
$ tanzu apps cluster-supply-chain list
NAME                         READY   AGE
scanning-image-scan-to-url   Ready   22m
source-test-scan-to-url      Ready   22m
kubectl apply -f - -n demo << 'EOF'
---
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: skip-test-pipeline
  labels:
    apps.tanzu.vmware.com/pipeline: test
    apps.tanzu.vmware.com/language: skip
spec:
  params:
  - name: source-url
  - name: source-revision
  tasks:
  - name: test
    params:
    - name: source-url
      value: $(params.source-url)
    - name: source-revision
      value: $(params.source-revision)
    taskSpec:
      params:
      - name: source-url
      - name: source-revision
      steps:
      - name: test
        image: alpine
        script: |-
          echo 'skip'
---
EOF
kubectl apply -f - -n demo << 'EOF'
---
apiVersion: scanning.apps.tanzu.vmware.com/v1beta1
kind: ScanPolicy
metadata:
  labels:
    app.kubernetes.io/part-of: enable-in-gui
  name: scan-policy
spec:
  regoFile: |
    package main
    
    # Accepted Values: "Critical", "High", "Medium", "Low", "Negligible", "UnknownSeverity"
    notAllowedSeverities := ["UnknownSeverity"]
    
    ignoreCves := []
    
    contains(array, elem) = true {
      array[_] = elem
    } else = false { true }
    
    isSafe(match) {
      severities := { e | e := match.ratings.rating.severity } | { e | e := match.ratings.rating[_].severity }
      some i
      fails := contains(notAllowedSeverities, severities[i])
      not fails
    }
    
    isSafe(match) {
      ignore := contains(ignoreCves, match.id)
      ignore
    }
    
    deny[msg] {
      comps := { e | e := input.bom.components.component } | { e | e := input.bom.components.component[_] }
      some i
      comp := comps[i]
      vulns := { e | e := comp.vulnerabilities.vulnerability } | { e | e := comp.vulnerabilities.vulnerability[_] }
      some j
      vuln := vulns[j]
      ratings := { e | e := vuln.ratings.rating.severity } | { e | e := vuln.ratings.rating[_].severity }
      not isSafe(vuln)
      msg = sprintf("CVE %s %s %s", [comp.name, vuln.id, ratings])
    }
---
EOF
WORKLOADNAME=hello-nodejs
NAMESPACE=demo

aws ecr create-repository --repository-name tanzu-application-platform/${WORKLOADNAME}-${NAMESPACE} --region $AWS_REGION
aws ecr create-repository --repository-name tanzu-application-platform/${WORKLOADNAME}-${NAMESPACE}-bundle --region $AWS_REGION
tanzu apps workload apply hello-nodejs \
  --app hello-nodejs \
  --git-repo https://github.com/making/hello-nodejs \
  --git-branch master \
  --type web \
  --label apps.tanzu.vmware.com/has-tests=true \
  -n demo \
  -y
tanzu apps workload tail hello-nodejs --namespace demo --timestamp --since 1h
$ tanzu apps workload get hello-nodejs --namespace demo       
📡 Overview
   name:        hello-nodejs
   type:        web
   namespace:   demo

💾 Source
   type:       git
   url:        https://github.com/making/hello-nodejs
   branch:     master
   revision:   master@sha1:76f84e92aa878f170b5b5010bf4cd7cabfbf7e53

📦 Supply Chain
   name:   source-test-scan-to-url

   NAME               READY   HEALTHY   UPDATED   RESOURCE
   source-provider    True    True      5m49s     gitrepositories.source.toolkit.fluxcd.io/hello-nodejs
   source-tester      True    True      5m16s     runnables.carto.run/hello-nodejs
   image-provider     True    True      112s      images.kpack.io/hello-nodejs
   image-scanner      True    True      77s       imagescans.scanning.apps.tanzu.vmware.com/hello-nodejs
   config-provider    True    True      74s       podintents.conventions.carto.run/hello-nodejs
   app-config         True    True      74s       configmaps/hello-nodejs
   service-bindings   True    True      74s       configmaps/hello-nodejs-with-claims
   api-descriptors    True    True      74s       configmaps/hello-nodejs-with-api-descriptors
   config-writer      True    True      49s       taskruns.tekton.dev/hello-nodejs-config-writer-7wxcs

🚚 Delivery
   name:   delivery-basic

   NAME              READY   HEALTHY   UPDATED   RESOURCE
   source-provider   True    True      45s       imagerepositories.source.apps.tanzu.vmware.com/hello-nodejs-delivery
   deployer          True    True      32s       apps.kappctrl.k14s.io/hello-nodejs

💬 Messages
   No messages found.

🛶 Pods
   NAME                                            READY   STATUS      RESTARTS   AGE
   hello-nodejs-00001-deployment-c67ff4c65-g8lnq   2/2     Running     0          45s
   hello-nodejs-build-1-build-pod                  0/1     Completed   0          5m16s
   hello-nodejs-config-writer-7wxcs-pod            0/1     Completed   0          73s
   hello-nodejs-jm5hb-test-pod                     0/1     Completed   0          5m44s
   scan-hello-nodejs-6kwmp-pod                     0/6     Completed   0          111s

🚢 Knative Services
   NAME           READY   URL
   hello-nodejs   Ready   https://hello-nodejs.demo.tap.52.69.252.111.sslip.io

To see logs: "tanzu apps workload tail hello-nodejs --namespace demo --timestamp --since 1h"
$ curl -k https://hello-nodejs.demo.tap.52.69.252.111.sslip.io

Hello World!!! (hello-nodejs-00001-deployment-c67ff4c65-ctjhd)
image image image image

Let's Encrypt (HTTP01 challenge)のClusterIssuerを作成

$ kubectl get certificate -A -owide | grep 'tap-ingress-selfsigned '
api-auto-registration       api-auto-registration-cert                   True    api-auto-registration-cert                   tap-ingress-selfsigned                       Certificate is up to date and has not expired   38m
demo                        route-8704ec08-eeab-457a-8e43-c3399b5b1b55   True    route-8704ec08-eeab-457a-8e43-c3399b5b1b55   tap-ingress-selfsigned                       Certificate is up to date and has not expired   2m22s
metadata-store              amr-cloudevent-handler-ingress-cert          True    amr-cloudevent-handler-ingress-cert          tap-ingress-selfsigned                       Certificate is up to date and has not expired   38m
metadata-store              amr-ingress-cert                             True    amr-ingress-cert                             tap-ingress-selfsigned                       Certificate is up to date and has not expired   38m
metadata-store              ingress-cert                                 True    ingress-cert                                 tap-ingress-selfsigned                       Certificate is up to date and has not expired   38m
tap-gui                     tap-gui-cert                                 True    tap-gui-cert                                 tap-ingress-selfsigned                       Certificate is up to date and has not expired   37m
cat <<EOF > cluster-issuer.yaml
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: user@yourdomain.com
    privateKeySecretRef:
      name: letsencrypt
    solvers:
    - http01:
        ingress:
          class: contour
---
EOF
kubectl apply -f cluster-issuer.yaml
shared:
  ingress_domain: ...
  ingress_issuer: letsencrypt
# ...
tanzu package install tap -p tap.tanzu.vmware.com -v 1.7.3 --values-file tap-values.yaml -n tap-install 
$ kubectl get certificate -A -owide | grep letsencrypt
api-auto-registration       api-auto-registration-cert                   False   api-auto-registration-cert                   letsencrypt                                  Fields on existing CertificateRequest resource not up to date: [spec.issuerRef]   39m
demo                        route-8704ec08-eeab-457a-8e43-c3399b5b1b55   False   route-8704ec08-eeab-457a-8e43-c3399b5b1b55   letsencrypt                                  Fields on existing CertificateRequest resource not up to date: [spec.issuerRef]   3m42s
metadata-store              amr-cloudevent-handler-ingress-cert          False   amr-cloudevent-handler-ingress-cert          letsencrypt                                  Fields on existing CertificateRequest resource not up to date: [spec.issuerRef]   39m
metadata-store              amr-ingress-cert                             False   amr-ingress-cert                             letsencrypt                                  Fields on existing CertificateRequest resource not up to date: [spec.issuerRef]   39m
metadata-store              ingress-cert                                 False   ingress-cert                                 letsencrypt                                  Fields on existing CertificateRequest resource not up to date: [spec.issuerRef]   39m
tap-gui                     tap-gui-cert                                 False   tap-gui-cert                                 letsencrypt                                  Fields on existing CertificateRequest resource not up to date: [spec.issuerRef]   39m
$ kubectl get pod -n demo
NAME                                            READY   STATUS      RESTARTS   AGE
cm-acme-http-solver-82bz9                       1/1     Running     0          25s
hello-nodejs-00001-deployment-c67ff4c65-r59ts   2/2     Running     0          25s
hello-nodejs-build-1-build-pod                  0/1     Completed   0          8m27s
hello-nodejs-config-writer-7wxcs-pod            0/1     Completed   0          4m24s
hello-nodejs-jm5hb-test-pod                     0/1     Completed   0          8m55s
scan-hello-nodejs-6kwmp-pod                     0/6     Completed   0          5m2s
$ kubectl get certificate -A -owide | grep letsencrypt
api-auto-registration       api-auto-registration-cert                   True    api-auto-registration-cert                   letsencrypt                                  Certificate is up to date and has not expired   40m
demo                        route-8704ec08-eeab-457a-8e43-c3399b5b1b55   True    route-8704ec08-eeab-457a-8e43-c3399b5b1b55   letsencrypt                                  Certificate is up to date and has not expired   4m31s
metadata-store              amr-cloudevent-handler-ingress-cert          True    amr-cloudevent-handler-ingress-cert          letsencrypt                                  Certificate is up to date and has not expired   40m
metadata-store              amr-ingress-cert                             True    amr-ingress-cert                             letsencrypt                                  Certificate is up to date and has not expired   40m
metadata-store              ingress-cert                                 True    ingress-cert                                 letsencrypt                                  Certificate is up to date and has not expired   40m
tap-gui                     tap-gui-cert                                 True    tap-gui-cert                                 letsencrypt                                  Certificate is up to date and has not expired   40m
$ curl https://hello-nodejs.demo.tap.52.69.252.111.sslip.io

Hello World!!! (hello-nodejs-00001-deployment-c67ff4c65-5x684)
image

(Optional) Metrics Serverのインストール

tanzu package repository add tanzu-core \
  --url projects.registry.vmware.com/tkg/packages/core/repo:v1.27.5_vmware.1-tkg.3 \
  --namespace tkg-system \
  --create-namespace 
tanzu package install -n tkg-system metrics-server -p metrics-server.tanzu.vmware.com -v 0.6.2+vmware.1-tkg.4
$ kubectl get deploy -n kube-system metrics-server
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
metrics-server   1/1     1            1           79s
$ kubectl top node
NAME                                                CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
ip-192-168-19-134.ap-northeast-1.compute.internal   195m         4%     1797Mi          12%       
ip-192-168-39-153.ap-northeast-1.compute.internal   93m          2%     1340Mi          9%        
ip-192-168-79-97.ap-northeast-1.compute.internal    101m         2%     1930Mi          13% 

Local Source Proxy

mkdir -p hello-world/public
cd hello-world
cat <<EOF > public/index.html
<!DOCTYPE html>
<html>
  <head>
    <title>Hello World!</title>
  </head>
  <body>
    <p>Hello World!</p>
  </body>
</html>
EOF
WORKLOADNAME=hello-world
NAMESPACE=demo

aws ecr create-repository --repository-name tanzu-application-platform/${WORKLOADNAME}-${NAMESPACE} --region $AWS_REGION
aws ecr create-repository --repository-name tanzu-application-platform/${WORKLOADNAME}-${NAMESPACE}-bundle --region $AWS_REGION
tanzu apps workload apply hello-world \
  --local-path ./ \
  --type web \
  --app hello-world \
  --label apps.tanzu.vmware.com/has-tests=true \
  --build-env BP_WEB_SERVER=nginx \
  -n demo \
  -y
cd ..
tanzu apps workload tail hello-world --namespace demo --timestamp --since 1h
$ tanzu apps workload get -n demo hello-world
📡 Overview
   name:        hello-world
   type:        web
   namespace:   demo

💾 Source
   type:    source image
   image:   532912407632.dkr.ecr.ap-northeast-1.amazonaws.com/tap-lsp:demo-hello-world@sha256:cff5552ec1c0e57e14f7ff7060bc308fd8f002facdf683795814130d73258aa0

📦 Supply Chain
   name:   source-test-scan-to-url

   NAME               READY   HEALTHY   UPDATED   RESOURCE
   source-provider    True    True      5m39s     imagerepositories.source.apps.tanzu.vmware.com/hello-world
   source-tester      True    True      5m11s     runnables.carto.run/hello-world
   image-provider     True    True      113s      images.kpack.io/hello-world
   image-scanner      True    True      83s       imagescans.scanning.apps.tanzu.vmware.com/hello-world
   config-provider    True    True      80s       podintents.conventions.carto.run/hello-world
   app-config         True    True      80s       configmaps/hello-world
   service-bindings   True    True      79s       configmaps/hello-world-with-claims
   api-descriptors    True    True      79s       configmaps/hello-world-with-api-descriptors
   config-writer      True    True      70s       taskruns.tekton.dev/hello-world-config-writer-5gs4x

🚚 Delivery
   name:   delivery-basic

   NAME              READY   HEALTHY   UPDATED   RESOURCE
   source-provider   True    True      38s       imagerepositories.source.apps.tanzu.vmware.com/hello-world-delivery
   deployer          True    True      3s        apps.kappctrl.k14s.io/hello-world

💬 Messages
   No messages found.

🛶 Pods
   NAME                                            READY   STATUS      RESTARTS   AGE
   hello-world-00001-deployment-5f78b64f79-lp9zr   2/2     Running     0          37s
   hello-world-build-1-build-pod                   0/1     Completed   0          5m10s
   hello-world-config-writer-5gs4x-pod             0/1     Completed   0          79s
   hello-world-hd45c-test-pod                      0/1     Completed   0          5m36s
   scan-hello-world-mxjpt-pod                      0/6     Completed   0          113s

🚢 Knative Services
   NAME          READY   URL
   hello-world   Ready   https://hello-world.demo.tap.52.69.252.111.sslip.io

To see logs: "tanzu apps workload tail hello-world --namespace demo --timestamp --since 1h"
$ curl https://hello-world.demo.tap.52.69.252.111.sslip.io
<!DOCTYPE html>
<html>
  <head>
    <title>Hello World!</title>
  </head>
  <body>
    <p>Hello World!</p>
  </body>
</html>

Bitnami ServiceでPostgreSQLを動的プロビジョニング

WORKLOADNAME=blog-api
NAMESPACE=demo

aws ecr create-repository --repository-name tanzu-application-platform/${WORKLOADNAME}-${NAMESPACE} --region $AWS_REGION
aws ecr create-repository --repository-name tanzu-application-platform/${WORKLOADNAME}-${NAMESPACE}-bundle --region $AWS_REGION
$ kubectl get clusterinstanceclass
NAME                   DESCRIPTION             READY   REASON
kafka-unmanaged        Kafka by Bitnami        True    Ready
mongodb-unmanaged      MongoDB by Bitnami      True    Ready
mysql-unmanaged        MySQL by Bitnami        True    Ready
postgresql-unmanaged   PostgreSQL by Bitnami   True    Ready
rabbitmq-unmanaged     RabbitMQ by Bitnami     True    Ready
redis-unmanaged        Redis by Bitnami        True    Ready
tanzu service class-claim create blog-db --class postgresql-unmanaged --parameter storageGB=1 -n demo
$ tanzu services class-claims get blog-db --namespace demo
Name: blog-db
Namespace: demo
Claim Reference: services.apps.tanzu.vmware.com/v1alpha1:ClassClaim:blog-db
Class Reference: 
  Name: postgresql-unmanaged
Parameters: 
  storageGB: 1
Status: 
  Ready: True
  Claimed Resource: 
    Name: 1503b835-872b-4dc7-a5f1-209ac1e69d63
    Namespace: demo
    Group: 
    Version: v1
    Kind: Secret
$ kubectl get secret -n demo 1503b835-872b-4dc7-a5f1-209ac1e69d63 -ojson | jq '.data | map_values(@base64d)'
{
  "database": "blog-db-mjj8p",
  "host": "10.100.45.57",
  "password": "qD9dZ20PDmTCiNo8vOj5Fd132HrnOmx8",
  "port": "5432",
  "provider": "bitnami",
  "type": "postgresql",
  "username": "postgres"
}
$ kubectl get sts -A
NAMESPACE        NAME                READY   AGE
blog-db-mjj8p    blog-db-mjj8p       1/1     1h24m
metadata-store   metadata-store-db   1/1     2h58m
tanzu apps workload apply blog-api \
  --app blog-api \
  --git-repo https://github.com/categolj/blog-api \
  --git-branch main \
  --type web \
  --annotation autoscaling.knative.dev/minScale=1 \
  --label apps.tanzu.vmware.com/has-tests=true \
  --service-ref blog-db=services.apps.tanzu.vmware.com/v1alpha1:ClassClaim:blog-db \
  --build-env BP_JVM_VERSION=17 \
  -n demo \
  -y
tanzu apps workload tail blog-api --namespace demo --timestamp --since 1h
$ tanzu apps workload get -n demo blog-api
📡 Overview
   name:        blog-api
   type:        web
   namespace:   demo

💾 Source
   type:       git
   url:        https://github.com/categolj/blog-api
   branch:     main
   revision:   main@sha1:ee957ac5ce3a96db766008217e4f3bf0968af540

📦 Supply Chain
   name:   source-test-scan-to-url

   NAME               READY   HEALTHY   UPDATED   RESOURCE
   source-provider    True    True      37m       gitrepositories.source.toolkit.fluxcd.io/blog-api
   source-tester      True    True      37m       runnables.carto.run/blog-api
   image-provider     True    True      29m       images.kpack.io/blog-api
   image-scanner      True    True      28m       imagescans.scanning.apps.tanzu.vmware.com/blog-api
   config-provider    True    True      28m       podintents.conventions.carto.run/blog-api
   app-config         True    True      28m       configmaps/blog-api
   service-bindings   True    True      28m       configmaps/blog-api-with-claims
   api-descriptors    True    True      28m       configmaps/blog-api-with-api-descriptors
   config-writer      True    True      28m       taskruns.tekton.dev/blog-api-config-writer-hjn29

🚚 Delivery
   name:   delivery-basic

   NAME              READY   HEALTHY   UPDATED   RESOURCE
   source-provider   True    True      27m       imagerepositories.source.apps.tanzu.vmware.com/blog-api-delivery
   deployer          True    True      26m       apps.kappctrl.k14s.io/blog-api

💬 Messages
   No messages found.

🔁 Services
   CLAIM     NAME      KIND         API VERSION
   blog-db   blog-db   ClassClaim   services.apps.tanzu.vmware.com/v1alpha1

🛶 Pods
   NAME                                         READY   STATUS      RESTARTS   AGE
   blog-api-00001-deployment-5766885df6-dwcds   2/2     Running     0          27m
   blog-api-6mvh2-test-pod                      0/1     Completed   0          37m
   blog-api-build-1-build-pod                   0/1     Completed   0          37m
   blog-api-config-writer-hjn29-pod             0/1     Completed   0          28m
   scan-blog-api-wlwdm-pod                      0/6     Completed   0          29m

🚢 Knative Services
   NAME       READY   URL
   blog-api   Ready   https://blog-api.demo.tap.52.69.252.111.sslip.io
curl -s https://blog-api.demo.tap.52.69.252.111.sslip.io/entries/template.md > template.md
curl -s -u admin:changeme -XPUT https://blog-api.demo.tap.52.69.252.111.sslip.io/entries/1 -H "Content-Type: text/markdown" -d "$(cat template.md)"
curl -s https://blog-api.demo.tap.52.69.252.111.sslip.io/entries/1 | jq .

{
  "entryId": 1,
  "frontMatter": {
    "title": "Welcome to CategolJ!",
    "categories": [
      {
        "name": "Blog"
      },
      {
        "name": "Posts"
      },
      {
        "name": "Templates"
      }
    ],
    "tags": [
      {
        "name": "Hello World"
      },
      {
        "name": "CategolJ"
      }
    ]
  },
  "content": "Welcome\n\n**Hello world**, this is my first Categolj blog post.\n\nI hope you like it!",
  "created": {
    "name": "admin",
    "date": "2023-12-13T07:24:29.851875Z"
  },
  "updated": {
    "name": "admin",
    "date": "2023-12-13T07:24:29.851875Z"
  }
}

App Live View

image

https://github.com/categolj/tap-catalog-info/blob/main/blog-api.yaml

image image image image image image image image image

AWS ServicesでRDSの動的プロビジョニング

PRIVATE_SUBNET_ID_1=$(aws ec2 describe-subnets --filters "Name=tag:Name,Values=eksctl-$(echo $EKS_CLUSTER_NAME)-cluster/SubnetPrivate$(echo $AWS_REGION | tr 'a-z' 'A-Z' | tr -d '-')A" --query "Subnets[*].SubnetId" --output text) 
PRIVATE_SUBNET_ID_2=$(aws ec2 describe-subnets --filters "Name=tag:Name,Values=eksctl-$(echo $EKS_CLUSTER_NAME)-cluster/SubnetPrivate$(echo $AWS_REGION | tr 'a-z' 'A-Z' | tr -d '-')C" --query "Subnets[*].SubnetId" --output text) 
PRIVATE_SUBNET_ID_3=$(aws ec2 describe-subnets --filters "Name=tag:Name,Values=eksctl-$(echo $EKS_CLUSTER_NAME)-cluster/SubnetPrivate$(echo $AWS_REGION | tr 'a-z' 'A-Z' | tr -d '-')D" --query "Subnets[*].SubnetId" --output text) 
aws rds create-db-subnet-group \
    --db-subnet-group-name tap-aws-services \
    --db-subnet-group-description "TAP AWS Services Subnet Group" \
    --subnet-ids "[\"$PRIVATE_SUBNET_ID_1\", \"$PRIVATE_SUBNET_ID_2\", \"$PRIVATE_SUBNET_ID_3\"]" \
    --region $AWS_REGION
PUBLIC_SUBNET_ID_1=$(aws ec2 describe-subnets --filters "Name=tag:Name,Values=eksctl-$(echo $EKS_CLUSTER_NAME)-cluster/SubnetPublic$(echo $AWS_REGION | tr 'a-z' 'A-Z' | tr -d '-')A" --query "Subnets[*].SubnetId" --output text) 
PUBLIC_SUBNET_ID_2=$(aws ec2 describe-subnets --filters "Name=tag:Name,Values=eksctl-$(echo $EKS_CLUSTER_NAME)-cluster/SubnetPublic$(echo $AWS_REGION | tr 'a-z' 'A-Z' | tr -d '-')C" --query "Subnets[*].SubnetId" --output text) 
PUBLIC_SUBNET_ID_3=$(aws ec2 describe-subnets --filters "Name=tag:Name,Values=eksctl-$(echo $EKS_CLUSTER_NAME)-cluster/SubnetPublic$(echo $AWS_REGION | tr 'a-z' 'A-Z' | tr -d '-')D" --query "Subnets[*].SubnetId" --output text) 
VPC_ID=$(aws ec2 describe-vpcs --filters "Name=tag:Name,Values=eksctl-${EKS_CLUSTER_NAME}-cluster/VPC" --query "Vpcs[0].VpcId" --output text)
SG_ID=$(aws ec2 create-security-group --group-name tap-aws-services-postgresql --description "TAP AWS Services PostgreSQL" --tag-specifications 'ResourceType=security-group,Tags=[{Key=Name,Value=tap-aws-services-postgresql}]' --vpc-id $VPC_ID --region $AWS_REGION --query 'GroupId' --output text) 
aws ec2 authorize-security-group-ingress --group-id $SG_ID --protocol tcp --port 5432 --cidr $(aws ec2 describe-subnets --subnet-ids $PUBLIC_SUBNET_ID_1 --query 'Subnets[0].CidrBlock' --output text)
aws ec2 authorize-security-group-ingress --group-id $SG_ID --protocol tcp --port 5432 --cidr $(aws ec2 describe-subnets --subnet-ids $PUBLIC_SUBNET_ID_2 --query 'Subnets[0].CidrBlock' --output text)
aws ec2 authorize-security-group-ingress --group-id $SG_ID --protocol tcp --port 5432 --cidr $(aws ec2 describe-subnets --subnet-ids $PUBLIC_SUBNET_ID_3 --query 'Subnets[0].CidrBlock' --output text)
$ aws ec2 describe-security-groups --group-ids $SG_ID --output yaml 
SecurityGroups:
- Description: TAP AWS Services PostgreSQL
  GroupId: sg-09392b8928b5ea869
  GroupName: tap-aws-services-postgresql
  IpPermissions:
  - FromPort: 5432
    IpProtocol: tcp
    IpRanges:
    - CidrIp: 192.168.64.0/19
    - CidrIp: 192.168.0.0/19
    - CidrIp: 192.168.32.0/19
    Ipv6Ranges: []
    PrefixListIds: []
    ToPort: 5432
    UserIdGroupPairs: []
  IpPermissionsEgress:
  - IpProtocol: '-1'
    IpRanges:
    - CidrIp: 0.0.0.0/0
    Ipv6Ranges: []
    PrefixListIds: []
    UserIdGroupPairs: []
  OwnerId: '532912407632'
  Tags:
  - Key: Name
    Value: tap-aws-services-postgresql
  VpcId: vpc-045d0ec148d20f5e1
cat <<EOF > aws-services-values.yaml
---
postgresql:
  enabled: true
  region: ${AWS_REGION}
  provider_config_ref:
    name: aws-provider
  infrastructure:
    subnet_group:
      name: tap-aws-services
    security_groups:
    - id: ${SG_ID}
  instance_configuration:
    instance_class: db.t4g.micro
    engine_version: "15.5" # See aws rds describe-db-engine-versions --default-only --engine postgres --output yaml
    skip_final_snapshot: true
    publicly_accessible: false
    maintenance_window: Mon:00:00-Mon:03:00
---
EOF

https://github.com/upbound/provider-aws/blob/main/AUTHENTICATION.md#authentication-using-irsa

cat << EOF > aws-services-trust-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDCPROVIDER}"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "${OIDCPROVIDER}:aud": "sts.amazonaws.com"
                },
                "StringLike": {
                    "${OIDCPROVIDER}:sub": [
                        "system:serviceaccount:crossplane-system:provider-aws-*"
                    ]
                }
            }
        }
    ]
}
EOF

cat <<EOF > aws-services-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "rds:CreateDBInstance",
        "rds:DeleteDBInstance",
        "rds:DescribeDBInstances",
        "rds:StopDBInstance",
        "rds:StartDBInstance",
        "rds:ModifyDBInstance",
        "rds:AddTagsToResource",
        "rds:DescribeDBSubnetGroups",
        "rds:ListTagsForResource",
        "ec2:DescribeSecurityGroups"
      ],
      "Resource": "*"
    }
  ]
}
EOF

aws iam create-role --role-name tap-aws-services --assume-role-policy-document file://aws-services-trust-policy.json
aws iam put-role-policy --role-name tap-aws-services --policy-name tapAwsServicesPolicy --policy-document file://aws-services-policy.json
cat <<EOF > aws-services-overlay.yaml
---
#@ load("@ytt:overlay", "overlay")
#@overlay/match by=overlay.subset({"kind": "ControllerConfig"}), expects="1+"
---
metadata:
  #@overlay/match missing_ok=True
  annotations:
    #@overlay/match missing_ok=True
    eks.amazonaws.com/role-arn: arn:aws:iam::${AWS_ACCOUNT_ID}:role/tap-aws-services
---
#! Placeholder CRD that allows us to create a ProviderConfig
#! before the actual Provider has been installed. Uses "exists"
#! annotation so that the real CRD can be installed by the Provider.
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: providerconfigs.aws.upbound.io
  annotations:
    kapp.k14s.io/exists: ""
spec:
  group: aws.upbound.io
  versions:
  - name: v1beta1
  names:
    kind: ProviderConfig
---
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: aws-provider
spec:
  credentials:
    source: IRSA
---
EOF
tanzu package install aws-services -p aws.services.tanzu.vmware.com --version 0.1.0 -n tap-install --values-file aws-services-values.yaml --ytt-overlay-file aws-services-overlay.yaml
$ kubectl get securitygroup,subnetgroup
NAME                                                    READY   SYNCED   EXTERNAL-NAME          AGE
securitygroup.ec2.aws.upbound.io/sg-09392b8928b5ea869   True    True     sg-09392b8928b5ea869   57s

NAME                                              READY   SYNCED   EXTERNAL-NAME      AGE
subnetgroup.rds.aws.upbound.io/tap-aws-services           True     tap-aws-services   51s

Warning

subnetgroupのSYNCEDFalseのままで、describeすると

reading RDS DB Subnet Group (tap-aws-services): InvalidParameterValue: Missing necessary credentials. Please check http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAM.ServiceLinkedRoles.html

というエラーが出ている場合は、AWSServiceRoleForRDS ロールがないと思われます。初めてRDSを使用する場合はこのエラーが出ます。

この場合は次のコマンドを実行してください。

aws iam create-service-linked-role --aws-service-name rds.amazonaws.com
$ tanzu service class list
  NAME                    DESCRIPTION                              
  kafka-unmanaged         Kafka by Bitnami                         
  mongodb-unmanaged       MongoDB by Bitnami                       
  mysql-unmanaged         MySQL by Bitnami                         
  postgresql-managed-aws  PostgreSQL databases powered by AWS RDS  <<-----
  postgresql-unmanaged    PostgreSQL by Bitnami                    
  rabbitmq-unmanaged      RabbitMQ by Bitnami                      
  redis-unmanaged         Redis by Bitnami 
tanzu service class-claim delete blog-db -n demo -y
tanzu service class-claim create blog-db --class postgresql-managed-aws --parameter storageGB=20 -n demo
image image
$ tanzu services class-claims get blog-db --namespace demo 
Name: blog-db
Namespace: demo
Claim Reference: services.apps.tanzu.vmware.com/v1alpha1:ClassClaim:blog-db
Class Reference: 
  Name: postgresql-managed-aws
Parameters: 
  storageGB: 20
Status: 
  Ready: True
  Claimed Resource: 
    Name: 52840e97-b5b6-45a4-a1f7-64cbad6e7608
    Namespace: demo
    Group: 
    Version: v1
    Kind: Secret
$ kubectl get instances.rds                                                                                               
NAME                  READY   SYNCED   EXTERNAL-NAME         AGE
blog-db-hwvwl-djcfz   True    True     blog-db-hwvwl-djcfz   5m10s
$ kubectl get secret -n demo 52840e97-b5b6-45a4-a1f7-64cbad6e7608 -ojson | jq '.data | map_values(@base64d)'
{
  "database": "postgres",
  "host": "blog-db-hwvwl-djcfz.crcoo11tlq3d.ap-northeast-1.rds.amazonaws.com",
  "password": "mH7DdYLfuIAyWdeEqavYNSjQxia",
  "port": "5432",
  "provider": "aws",
  "type": "postgresql",
  "username": "adminuser"
}
kubectl delete app blog-api -n demo
$ kubectl get app -n demo blog-api
NAME       DESCRIPTION   SINCE-DEPLOY   AGE
blog-api   Reconciling   10s            10s
$ kubectl logs -n demo -l app.kubernetes.io/component=run,app.kubernetes.io/part-of=blog-api -c workload --tail=-1 | grep 'rds\.'
{"@timestamp":"2023-12-15T04:01:41.986Z","log.level": "INFO","message":"Database: jdbc:postgresql://blog-db-hwvwl-djcfz.crcoo11tlq3d.ap-northeast-1.rds.amazonaws.com:5432/postgres (PostgreSQL 15.5)","ecs.version": "1.2.0","service.name":"blog-api","event.dataset":"blog-api","process.thread.name":"main","log.logger":"org.flywaydb.core.FlywayExecutor","traceId":"84bc2ae8b8ef5062b7df4d67ceb3021c","spanId":"23467c245fc9d590"}
curl -s https://blog-api.demo.tap.52.69.252.111.sslip.io/entries/template.md > template.md
curl -s -u admin:changeme -XPUT https://blog-api.demo.tap.52.69.252.111.sslip.io/entries/1 -H "Content-Type: text/markdown" -d "$(cat template.md)"
curl -s https://blog-api.demo.tap.52.69.252.111.sslip.io/entries/1 | jq .

Workloadのソースコード取得元にAWS CodeCommitを使用

⚠️ IAM Userの作成は許可されていないことがあります。VMware社員でCloud Gateを使ってアカウントを払い出している場合は以下のコマンドは許可されていません。

aws iam create-user --user-name tap-git
aws iam attach-user-policy --user-name tap-git --policy-arn arn:aws:iam::aws:policy/AWSCodeCommitFullAccess
aws iam create-service-specific-credential --user-name tap-git --service-name codecommit.amazonaws.com > codecommit-user.json
aws codecommit create-repository --repository-name hello-spring-boot --repository-description "Hello Spring Boot" --region $AWS_REGION > codecommit-repo.json
GIT_USERNAME=$(cat codecommit-user.json | jq -r .ServiceSpecificCredential.ServiceUserName)
GIT_PASSWORD=$(cat codecommit-user.json | jq -r .ServiceSpecificCredential.ServicePassword)
GIT_URL=$(cat codecommit-repo.json | jq -r .repositoryMetadata.cloneUrlHttp)

curl https://start.spring.io/starter.zip \
  -s \
  -d type=maven-project \
  -d language=java \
  -d bootVersion=3.2.0 \
  -d baseDir=hello-spring-boot \
  -d groupId=com.example \
  -d artifactId=hello-spring-boot \
  -d name=hello-spring-boot \
  -d description=Demo \
  -d packageName=com.example.demo \
  -d packaging=jar \
  -d javaVersion=17 \
  -d dependencies=web,actuator \
  -o hello-spring-boot.zip
unzip hello-spring-boot.zip 
cd hello-spring-boot

cat <<EOF > ./src/main/java/com/example/demo/HelloController.java
package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping(path = "/")
    public String hello() {
        return "Hello World!";
    }

}
EOF


git init
git add -A
git commit -m "initial commit"
git remote add origin https://$GIT_USERNAME:$GIT_PASSWORD@$(echo $GIT_URL | sed 's|https://||g')
git push origin main
image

https://docs.vmware.com/en/VMware-Tanzu-Application-Platform/1.7/tap/namespace-provisioner-use-case3.html

$ kubectl get sa -n demo default -oyaml
apiVersion: v1
imagePullSecrets:
- name: registries-credentials
kind: ServiceAccount
metadata:
# ...
  name: default
  namespace: demo
# ...
secrets:
- name: registries-credentials
cat << EOF > workload-git-auth.yaml
---
apiVersion: v1
kind: Secret
metadata:
  name: workload-git-auth
  namespace: tap-install
type: Opaque
stringData:
  content.yaml: |
    git:
      host: "https://git-codecommit.${AWS_REGION}.amazonaws.com" 
      username: "${GIT_USERNAME}"
      token: "${GIT_PASSWORD}"
---
EOF

kubectl apply -f workload-git-auth.yaml
cat <<EOF >> tap-values.yaml

namespace_provisioner:
  controller: true
  additional_sources:
  - git:
      url: https://github.com/making/namespace-provisioner-samples.git
      ref: origin/main
      subPath: git-basic
    path: _ytt_lib/git-basic
  import_data_values_secrets:
  - name: workload-git-auth
    namespace: tap-install
    create_export: true
  default_parameters:
    supply_chain_service_account:
      secrets:
      - git-basic
EOF
tanzu package install tap -p tap.tanzu.vmware.com -v 1.7.3 --values-file tap-values.yaml -n tap-install
$ kubectl get sa -n demo default -oyaml
apiVersion: v1
imagePullSecrets:
- name: registries-credentials
kind: ServiceAccount
metadata:
# ...
  name: default
  namespace: demo
# ...
secrets:
- name: registries-credentials
- name: git-basic  # <<----
$ kubectl get secret -n demo git-basic
NAME        TYPE                       DATA   AGE
git-basic   kubernetes.io/basic-auth   2      3m49s
WORKLOADNAME=hello-spring-boot
NAMESPACE=demo

aws ecr create-repository --repository-name tanzu-application-platform/${WORKLOADNAME}-${NAMESPACE} --region $AWS_REGION
aws ecr create-repository --repository-name tanzu-application-platform/${WORKLOADNAME}-${NAMESPACE}-bundle --region $AWS_REGION
tanzu apps workload apply hello-spring-boot \
  --app hello-spring-boot \
  --git-repo $GIT_URL \
  --git-branch main \
  --type web \
  --param gitops_ssh_secret=git-basic \
  --annotation autoscaling.knative.dev/minScale=1 \
  --label apps.tanzu.vmware.com/has-tests=true \
  --build-env BP_JVM_VERSION=17 \
  -n demo \
  -y
tanzu apps workload tail hello-spring-boot --namespace demo --timestamp --since 1h
$ tanzu apps workload get hello-spring-boot --namespace demo
📡 Overview
   name:        hello-spring-boot
   type:        web
   namespace:   demo

💾 Source
   type:       git
   url:        https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/hello-spring-boot
   branch:     main
   revision:   main@sha1:15120369817b61428602e1d28a1e083ccc14bea3

📦 Supply Chain
   name:   source-test-scan-to-url

   NAME               READY   HEALTHY   UPDATED   RESOURCE
   source-provider    True    True      6m38s     gitrepositories.source.toolkit.fluxcd.io/hello-spring-boot
   source-tester      True    True      6m22s     runnables.carto.run/hello-spring-boot
   image-provider     True    True      2m48s     images.kpack.io/hello-spring-boot
   image-scanner      True    True      2m14s     imagescans.scanning.apps.tanzu.vmware.com/hello-spring-boot
   config-provider    True    True      2m7s      podintents.conventions.carto.run/hello-spring-boot
   app-config         True    True      2m7s      configmaps/hello-spring-boot
   service-bindings   True    True      2m7s      configmaps/hello-spring-boot-with-claims
   api-descriptors    True    True      2m7s      configmaps/hello-spring-boot-with-api-descriptors
   config-writer      True    True      2m2s      taskruns.tekton.dev/hello-spring-boot-config-writer-dddmc

🚚 Delivery
   name:   delivery-basic

   NAME              READY   HEALTHY   UPDATED   RESOURCE
   source-provider   True    True      100s      imagerepositories.source.apps.tanzu.vmware.com/hello-spring-boot-delivery
   deployer          True    True      59s       apps.kappctrl.k14s.io/hello-spring-boot

💬 Messages
   No messages found.

🛶 Pods
   NAME                                                  READY   STATUS      RESTARTS   AGE
   hello-spring-boot-00001-deployment-5c6c58b777-jg5bn   2/2     Running     0          99s
   hello-spring-boot-build-1-build-pod                   0/1     Completed   0          6m21s
   hello-spring-boot-config-writer-dddmc-pod             0/1     Completed   0          2m10s
   hello-spring-boot-v846b-test-pod                      0/1     Completed   0          6m35s
   scan-hello-spring-boot-v242b-pod                      0/6     Completed   0          2m48s

🚢 Knative Services
   NAME                READY   URL
   hello-spring-boot   Ready   https://hello-spring-boot.demo.tap.52.69.252.111.sslip.io
$ curl https://hello-spring-boot.demo.tap.52.69.252.111.sslip.io
Hello World!
sed -i.bak 's/Hello World/Hello TAP/' src/main/java/com/example/demo/HelloController.java
rm -f src/main/java/com/example/demo/HelloController.java.bak
git add src/main/java/com/example/demo/HelloController.java
git commit -m "Update"
git push origin main
tanzu apps workload tail hello-spring-boot --namespace demo --timestamp --since 5m
$ curl https://hello-spring-boot.demo.tap.52.69.252.111.sslip.io
Hello TAP!

EnvoyのLoad Balancerに対するInboundのIP制限

https://repost.aws/knowledge-center/eks-cidr-ip-address-loadbalancer

cat <<EOF > contour-envoy-lb-source-ranges.yaml
---
apiVersion: v1
kind: Secret
metadata:
  name: contour-envoy-lb-source-ranges
  namespace: tap-install
type: Opaque
stringData:
  contour-envoy-lb-source-ranges.yaml: |
    #@ load("@ytt:overlay", "overlay")
    #@overlay/match by=overlay.subset({"kind": "Service", "metadata": {"name": "envoy"}})
    ---
    spec:
      #@overlay/match missing_ok=True
      loadBalancerSourceRanges:
      - 66.170.99.1/32
      - 57.181.54.124/32
---
EOF

kubectl apply -f contour-envoy-lb-source-ranges.yaml
cat <<EOF >> tap-values.yaml

package_overlays:
- name: contour
  secrets:
  - name: contour-envoy-lb-source-ranges
EOF

⚠️ この方法を使用すると、Let's EncryptによるHTTP-01チャレンジができなくなります。(証明書が生成されなくなります)

チャレンジ方式をDNS-01にする (Route53などpublicなDNSサービスが必要です) か、shared.ingress_issuerの設定を削除して、自己署名証明書に戻す必要があります。

tanzu package install tap -p tap.tanzu.vmware.com -v 1.7.3 --values-file tap-values.yaml -n tap-install
$ kubectl get svc -n tanzu-system-ingress envoy -ojsonpath='{.spec.loadBalancerSourceRanges}'
["66.170.99.1/32","57.181.54.124/32"]
image

アンインストール

kubectl delete workload -A --all
kubectl delete classclaim -A --all
tanzu package installed delete -n tap-install aws-services -y
tanzu package installed delete -n tap-install full-deps -y
tanzu package installed delete -n tap-install tap -y
kubectl delete pvc -A --all
aws ec2 delete-security-group --group-id ${SG_ID} --region $AWS_REGION
aws rds delete-db-subnet-group --db-subnet-group-name tap-aws-services --region $AWS_REGION
aws iam delete-role-policy --role-name tap-aws-services --policy-name tapAwsServicesPolicy
aws iam delete-role --role-name tap-aws-services
aws iam delete-role-policy --role-name tap-build-service --policy-name tapBuildServicePolicy
aws iam delete-role-policy --role-name tap-workload --policy-name tapWorkload
aws iam delete-role-policy --role-name tap-local-source-proxy --policy-name tapLocalSourcePolicy
aws iam delete-role --role-name tap-build-service
aws iam delete-role --role-name tap-workload
aws iam delete-role --role-name tap-local-source-proxy
aws ecr delete-repository --repository-name tap-images --force --region $AWS_REGION
aws ecr delete-repository --repository-name tap-build-service --force --region $AWS_REGION

aws ecr delete-repository --repository-name full-deps-package-repo --force --region $AWS_REGION
aws ecr delete-repository --repository-name tap-lsp --force --region $AWS_REGION
aws ecr delete-repository --repository-name tanzu-cluster-essentials --force --region $AWS_REGION

aws ecr delete-repository --repository-name tanzu-application-platform/hello-nodejs-demo --force --region $AWS_REGION
aws ecr delete-repository --repository-name tanzu-application-platform/hello-nodejs-demo-bundle --force --region $AWS_REGION
aws ecr delete-repository --repository-name tanzu-application-platform/hello-world-demo --force --region $AWS_REGION
aws ecr delete-repository --repository-name tanzu-application-platform/hello-world-demo-bundle --force --region $AWS_REGION

# ...
eksctl delete cluster -f eks-cluster-config.yaml --force --disable-nodegroup-eviction --parallel 3 --wait
aws ec2 release-address --allocation-id $(jq -r '.AllocationId' envoy-eip-1.json)
aws ec2 release-address --allocation-id $(jq -r '.AllocationId' envoy-eip-2.json)
aws ec2 release-address --allocation-id $(jq -r '.AllocationId' envoy-eip-3.json)
Found a mistake? Update the entry.