Create Spanner
Duration: 10 min | Persona: Platform Admin
In this section, you will create a Spanner instance and database for the Online Boutique’s cartservice
app to connect to. You will also configure the associated cartservice
’s Google Service account to have fine granular read access to the Spanner database via Workload Identity.
Initialize variables:
WORK_DIR=~/
source ${WORK_DIR}acm-workshop-variables.sh
echo "export SPANNER_INSTANCE_NAME=onlineboutique" >> ${WORK_DIR}acm-workshop-variables.sh
echo "export SPANNER_DATABASE_NAME=carts" >> ${WORK_DIR}acm-workshop-variables.sh
echo "export SPANNER_DATABASE_USER_GSA_NAME=spanner-db-user" >> ${WORK_DIR}acm-workshop-variables.sh
source ${WORK_DIR}acm-workshop-variables.sh
Define Spanner instance
Define the Spanner instance resource:
cat <<EOF > ${WORK_DIR}$TENANT_PROJECT_DIR_NAME/$ONLINEBOUTIQUE_NAMESPACE/spanner-instance.yaml
apiVersion: spanner.cnrm.cloud.google.com/v1beta1
kind: SpannerInstance
metadata:
annotations:
cnrm.cloud.google.com/project-id: ${TENANT_PROJECT_ID}
name: ${SPANNER_INSTANCE_NAME}
namespace: ${TENANT_PROJECT_ID}
spec:
config: regional-${GKE_LOCATION}
displayName: ${SPANNER_INSTANCE_NAME}
numNodes: 2
EOF
Define Spanner database
Define the Spanner database resource:
cat <<EOF > ${WORK_DIR}$TENANT_PROJECT_DIR_NAME/$ONLINEBOUTIQUE_NAMESPACE/spanner-database.yaml
apiVersion: spanner.cnrm.cloud.google.com/v1beta1
kind: SpannerDatabase
metadata:
name: ${SPANNER_DATABASE_NAME}
namespace: ${TENANT_PROJECT_ID}
annotations:
config.kubernetes.io/depends-on: spanner.cnrm.cloud.google.com/namespaces/${TENANT_PROJECT_ID}/SpannerInstance/${SPANNER_INSTANCE_NAME}
spec:
instanceRef:
name: ${SPANNER_INSTANCE_NAME}
databaseDialect: GOOGLE_STANDARD_SQL
ddl:
- "CREATE TABLE CartItems (userId STRING(1024), productId STRING(1024), quantity INT64,) PRIMARY KEY (userId, productId)"
- "CREATE INDEX CartItemsByUserId ON CartItems(userId)"
EOF
Grant the cartservice
’s service account access to the Spanner database
cat <<EOF > ${WORK_DIR}$TENANT_PROJECT_DIR_NAME/$ONLINEBOUTIQUE_NAMESPACE/spanner-db-user-service-account.yaml
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMServiceAccount
metadata:
annotations:
cnrm.cloud.google.com/project-id: ${TENANT_PROJECT_ID}
name: ${SPANNER_DATABASE_USER_GSA_NAME}
namespace: ${TENANT_PROJECT_ID}
spec:
displayName: ${SPANNER_DATABASE_USER_GSA_NAME}
EOF
cat <<EOF > ${WORK_DIR}$TENANT_PROJECT_DIR_NAME/$ONLINEBOUTIQUE_NAMESPACE/spanner-db-user.yaml
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
name: ${SPANNER_DATABASE_USER_GSA_NAME}
namespace: ${TENANT_PROJECT_ID}
annotations:
config.kubernetes.io/depends-on: iam.cnrm.cloud.google.com/namespaces/${TENANT_PROJECT_ID}/IAMServiceAccount/${SPANNER_DATABASE_USER_GSA_NAME},spanner.cnrm.cloud.google.com/namespaces/${TENANT_PROJECT_ID}/SpannerDatabase/${SPANNER_DATABASE_NAME}
spec:
memberFrom:
serviceAccountRef:
name: ${SPANNER_DATABASE_USER_GSA_NAME}
namespace: ${TENANT_PROJECT_ID}
resourceRef:
kind: SpannerDatabase
name: ${SPANNER_DATABASE_NAME}
role: roles/spanner.databaseUser
EOF
cat <<EOF > ${WORK_DIR}$TENANT_PROJECT_DIR_NAME/$ONLINEBOUTIQUE_NAMESPACE/spanner-db-user-workload-identity-user.yaml
apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPartialPolicy
metadata:
name: ${SPANNER_DATABASE_USER_GSA_NAME}
namespace: ${TENANT_PROJECT_ID}
annotations:
config.kubernetes.io/depends-on: iam.cnrm.cloud.google.com/namespaces/${TENANT_PROJECT_ID}/IAMServiceAccount/${SPANNER_DATABASE_USER_GSA_NAME}
spec:
resourceRef:
name: ${SPANNER_DATABASE_USER_GSA_NAME}
kind: IAMServiceAccount
bindings:
- role: roles/iam.workloadIdentityUser
members:
- member: serviceAccount:${TENANT_PROJECT_ID}.svc.id.goog[${ONLINEBOUTIQUE_NAMESPACE}/cartservice]
EOF
Deploy Kubernetes manifests
cd ${WORK_DIR}$TENANT_PROJECT_DIR_NAME/
git add . && git commit -m "Spanner instance and database and configure cartservice's gsa" && git push origin main
Check deployments
graph TD; SpannerInstance-.->Project SpannerDatabase-->SpannerInstance IAMServiceAccount-.->Project IAMPolicyMember-->SpannerDatabase IAMPolicyMember-->IAMServiceAccount
List the Kubernetes resources managed by Config Sync in Config Controller for the Tenant project configs repository:
Run this command and click on this link:
echo -e "https://console.cloud.google.com/kubernetes/config_management/packages?project=${HOST_PROJECT_ID}"
Wait until you see the Sync status
column as Synced
and the Reconcile status
column as Current
.
Run this command:
gcloud alpha anthos config sync repo describe \
--project $HOST_PROJECT_ID \
--managed-resources all \
--sync-name repo-sync \
--sync-namespace $TENANT_PROJECT_ID
Wait and re-run this command above until you see "status": "SYNCED"
. All the managed_resources
listed should have STATUS: Current
too.
List the GitHub runs for the Tenant project configs repository:
cd ${WORK_DIR}$TENANT_PROJECT_DIR_NAME && gh run list
List the Google Cloud resources created:
gcloud spanner instances list \
--project=$TENANT_PROJECT_ID
gcloud spanner databases list \
--instance $SPANNER_INSTANCE_NAME \
--project=$TENANT_PROJECT_ID
gcloud spanner databases get-iam-policy $SPANNER_DATABASE_NAME \
--project $TENANT_PROJECT_ID \
--instance $SPANNER_INSTANCE_NAME \
--filter="bindings.members:${SPANNER_DATABASE_USER_GSA_NAME}@${TENANT_PROJECT_ID}.iam.gserviceaccount.com" \
--flatten="bindings[].members" \
--format="table(bindings.role)"