Skip to content

Commit 9cdbc60

Browse files
authored
Fix shoppingassistant demo (#2675)
* Fix shoppingassistant demo * Tweak instruction README
1 parent 3b46ec0 commit 9cdbc60

File tree

9 files changed

+131
-398
lines changed

9 files changed

+131
-398
lines changed

kustomize/components/alloydb/kustomization.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ patches:
3434
- name: ALLOYDB_PRIMARY_IP
3535
value: ALLOYDB_PRIMARY_IP_VAL
3636
- name: ALLOYDB_DATABASE_NAME
37-
value: ALLOYDB_CARTS_DATABASE_NAME
37+
value: ALLOYDB_CARTS_DATABASE_NAME_VAL
3838
- name: ALLOYDB_TABLE_NAME
3939
value: ALLOYDB_CARTS_TABLE_NAME_VAL
4040
- name: ALLOYDB_SECRET_NAME

kustomize/components/shopping-assistant/README.md

+55-36
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,45 @@
11
# Shopping Assistant with RAG & AlloyDB
22

3-
This demo adds a new service to Online Boutique called `shoppingassistantservice`, which, alongside an Alloy-DB backed products catalog, adds a RAG-featured AI assistant to the frontned experience, which helps users suggest new products for their room decor.
3+
This demo adds a new service to Online Boutique called `shoppingassistantservice` which, alongside an Alloy-DB backed products catalog, adds a RAG-featured AI assistant to the frontned experience, helping users suggest products matching their home decor.
44

5-
## Set-up instructions
5+
## Setup instructions
66

7-
> Note: Make sure you have the `owner` role to the Google Cloud project you want to deploy this to, else you will be unable to enable certain APIs or modify certain VPC rules that are needed for this demo.
7+
**Note:** This demo requires a Google Cloud project where you to have the `owner` role, else you may be unable to enable APIs or modify VPC rules that are needed for this demo.
8+
9+
1. Set some environment variables.
10+
```sh
11+
export PROJECT_ID=<project_id>
12+
export PROJECT_NUMBER=<project_number>
13+
export PGPASSWORD=<pgpassword>
14+
```
15+
16+
**Note**: The project ID and project number of your Google Cloud project can be found in the Console. The PostgreSQL password can be set to anything you want, but make sure to note it down.
17+
18+
1. Change your default Google Cloud project.
19+
```sh
20+
gcloud auth login
21+
gcloud config set project $PROJECT_ID
22+
```
823

924
1. Enable the Google Kubernetes Engine (GKE) and Artifact Registry (AR) APIs.
1025
```sh
1126
gcloud services enable container.googleapis.com
1227
gcloud services enable artifactregistry.googleapis.com
1328
```
1429

15-
1. Create a GKE Autopilot cluster.
30+
1. Create a GKE Autopilot cluster. This may take a few minutes.
1631
```sh
1732
gcloud container clusters create-auto cymbal-shops \
1833
--region=us-central1
1934
```
2035

21-
1. Create an AR Docker image repository.
36+
1. Change your Kubernetes context to your newly created GKE cluster.
37+
```sh
38+
gcloud container clusters get-credentials cymbal-shops \
39+
--region us-central1
40+
```
41+
42+
1. Create an Artifact Registry container image repository.
2243
```sh
2344
gcloud artifacts repositories create images \
2445
--repository-format=docker \
@@ -31,26 +52,19 @@ This demo adds a new service to Online Boutique called `shoppingassistantservice
3152
&& cd microservices-demo/
3253
```
3354

34-
1. Context into the right project and GKE cluster.
55+
1. Run script #1. If it asks about policy bindings, select the option `None`. This may take a few minutes.
3556
```sh
36-
gcloud auth login
37-
gcloud config set project <PROJECT_ID>
38-
gcloud container clusters get-credentials cymbal-shops \
39-
--region us-central1
57+
./kustomize/components/shopping-assistant/scripts/1_deploy_alloydb_infra.sh
4058
```
4159

42-
1. Replace the placeholder variables into infra script #1 and run it. If it asks about policy bindings, select the option for "None".
43-
```sh
44-
vim kustomize/components/shopping-assistant/scripts/1_deploy_alloydb_infra.sh
45-
./scripts/1_deploy_alloydb_infra.sh
46-
```
60+
**Note**: If you are on macOS and use a non-GNU version of `sed`, you may have to tweak the script to use `gsed` instead.
4761

48-
1. Create micro Linux VM on GCP
62+
1. Create a Linux VM in Compute Engine (GCE).
4963
```sh
5064
gcloud compute instances create gce-linux \
5165
--zone=us-central1-a \
5266
--machine-type=e2-micro \
53-
--image-family=debian-12-bookworm-v20240312 \
67+
--image-family=debian-12 \
5468
--image-project=debian-cloud
5569
```
5670

@@ -60,62 +74,67 @@ This demo adds a new service to Online Boutique called `shoppingassistantservice
6074
--zone "us-central1-a"
6175
```
6276

63-
1. Install the Postgres client and context into the right project.
77+
1. Install the Postgres client and set your default Google Cloud project.
6478
```sh
6579
sudo apt-get install -y postgresql-client
6680
gcloud auth login
6781
gcloud config set project <PROJECT_ID>
6882
```
6983

70-
1. Copy script #2, the python script, and the updated products.json to the VM. Make sure the scripts are executable.
84+
1. Copy script #2, the python script, and the products.json to the VM. Make sure the scripts are executable.
7185
```sh
72-
vim 2_create_populate_alloydb_tables.sh
73-
vim generate_sql_from_products.py
74-
vim products.json
86+
nano 2_create_populate_alloydb_tables.sh # paste content
87+
nano generate_sql_from_products.py # paste content
88+
nano products.json # paste content
7589
chmod +x 2_create_populate_alloydb_tables.sh
7690
chmod +x generate_sql_from_products.py
7791
```
7892

79-
> Note: You can find the files at the following places:
80-
> - kustomize/components/shopping-assistant/scripts/2_create_populate_alloydb_tables.sh
81-
> - kustomize/components/shopping-assistant/scripts/generate_sql_from_products.py
82-
> - src/productcatalogservice/products.json
93+
**Note:** You can find the files at the following places:
94+
- `kustomize/components/shopping-assistant/scripts/2_create_populate_alloydb_tables.sh`
95+
- `kustomize/components/shopping-assistant/scripts/generate_sql_from_products.py`
96+
- `src/productcatalogservice/products.json`
8397

84-
1. Run script #2 in the VM. If it asks for a postgres password, it should be the same that you set in script #1 earlier.
98+
1. Run script #2 in the VM. If it asks for a postgres password, it should be the same that you set in script #1 earlier. This may take a few minutes.
8599
```sh
86100
./2_create_populate_alloydb_tables.sh
87101
```
88102

89-
1. Exit SSH
103+
1. Exit SSH.
90104
```sh
91105
exit
92106
```
93107

94108
1. Create an API key in the [Credentials page](https://pantheon.corp.google.com/apis/credentials) with permissions for "Generative Language API", and make note of the secret key.
95109

96-
1. Paste this secret key in the shopping assistant service envs, replacing `GOOGLE_API_KEY_VAL`.
110+
1. Replace the PostgreSQL password placeholder in the shoppingassistant service.
97111
```sh
98-
vim kustomize/components/shopping-assistant/shoppingassistantservice.yaml
112+
sed -i "s/GOOGLE_API_KEY_VAL/${PGPASSWORD}/g" kustomize/components/shopping-assistant/shoppingassistantservice.yaml
99113
```
100114

101-
1. Change the commented-out components in `kubernetes-manifests/kustomization.yaml` to look like this:
115+
1. Edit the root Kustomize file to enable the `alloydb` and `shopping-assistant` components.
116+
```sh
117+
nano kubernetes-manifests/kustomization.yaml # make the modifications below
118+
```
119+
102120
```yaml
103-
components: # remove comment
121+
# ...head of the file
122+
components: # remove this comment
104123
# - ../kustomize/components/cymbal-branding
105124
# - ../kustomize/components/google-cloud-operations
106125
# - ../kustomize/components/memorystore
107126
# - ../kustomize/components/network-policies
108-
- ../kustomize/components/alloydb # remove comment
109-
- ../kustomize/components/shopping-assistant # remove comment
127+
- ../kustomize/components/alloydb # remove this comment
128+
- ../kustomize/components/shopping-assistant # remove this comment
110129
# - ../kustomize/components/spanner
111130
# - ../kustomize/components/container-images-tag
112131
# - ../kustomize/components/container-images-tag-suffix
113132
# - ../kustomize/components/container-images-registry
114133
```
115134

116135
1. Deploy to the GKE cluster.
117-
```
118-
skaffold run --default-repo=us-central1-docker.pkg.dev/<PROJECT_ID>/images
136+
```sh
137+
skaffold run --default-repo=us-central1-docker.pkg.dev/$PROJECT_ID/images
119138
```
120139

121140
1. Wait for all the pods to be up and running. You can then find the external IP and navigate to it.

kustomize/components/shopping-assistant/scripts/1_deploy_alloydb_infra.sh

+5-7
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ set -e
1818
set -x
1919

2020
# Replace me
21-
PROJECT_ID=<project_id>
22-
PROJECT_NUMBER=<project_number>
23-
PGPASSWORD=<password>
21+
PROJECT_ID=$PROJECT_ID
22+
PROJECT_NUMBER=$PROJECT_NUMBER
23+
PGPASSWORD=$PGPASSWORD
2424

2525
# Set sensible defaults
2626
REGION=us-central1
@@ -82,7 +82,8 @@ gcloud alloydb instances create ${ALLOYDB_INSTANCE_NAME}-replica \
8282
gcloud beta alloydb instances update ${ALLOYDB_INSTANCE_NAME} \
8383
--cluster=${ALLOYDB_CLUSTER_NAME} \
8484
--region=${REGION} \
85-
--assign-inbound-public-ip=ASSIGN_IPV4
85+
--assign-inbound-public-ip=ASSIGN_IPV4 \
86+
--database-flags password.enforce_complexity=on
8687

8788
# Fetch the primary and read IPs
8889
ALLOYDB_PRIMARY_IP=`gcloud alloydb instances list --region=${REGION} --cluster=${ALLOYDB_CLUSTER_NAME} --filter="INSTANCE_TYPE:PRIMARY" --format=flattened | sed -nE "s/ipAddress:\s*(.*)/\1/p"`
@@ -119,9 +120,6 @@ gcloud projects add-iam-policy-binding ${PROJECT_ID} --member=serviceAccount:${A
119120
gcloud projects add-iam-policy-binding ${PROJECT_ID} --member=serviceAccount:${ALLOYDB_USER_GSA_ID} --role=roles/alloydb.databaseUser
120121
gcloud projects add-iam-policy-binding ${PROJECT_ID} --member=serviceAccount:${ALLOYDB_USER_GSA_ID} --role=roles/secretmanager.secretAccessor
121122
gcloud projects add-iam-policy-binding ${PROJECT_ID} --member=serviceAccount:${ALLOYDB_USER_GSA_ID} --role=roles/serviceusage.serviceUsageConsumer
122-
gcloud projects add-iam-policy-binding ${PROJECT_ID} --member=service-${PROJECT_NUMBER}@gcp-sa-alloydb.iam.gserviceaccount.com --role=roles/aiplatform.user
123-
124-
# Add bindings to the Online Boutique services that need it
125123
gcloud projects add-iam-policy-binding ${PROJECT_ID} --member=serviceAccount:service-${PROJECT_NUMBER}@gcp-sa-alloydb.iam.gserviceaccount.com --role=roles/aiplatform.user
126124

127125
gcloud iam service-accounts add-iam-policy-binding ${ALLOYDB_USER_GSA_ID} \

src/productcatalogservice/Dockerfile

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
FROM golang:1.22.5-alpine@sha256:0d3653dd6f35159ec6e3d10263a42372f6f194c3dea0b35235d72aabde86486e AS builder
15+
FROM golang:1.22.6-alpine@sha256:1a478681b671001b7f029f94b5016aed984a23ad99c707f6a0ab6563860ae2f3 AS builder
1616

1717
WORKDIR /src
1818
# restore dependencies
@@ -28,6 +28,7 @@ FROM scratch
2828

2929
WORKDIR /src
3030
COPY --from=builder /productcatalogservice ./server
31+
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
3132
COPY products.json .
3233

3334
# Definition of this variable is used by 'skaffold debug' to identify a golang binary.

src/productcatalogservice/catalog_loader.go

+13-3
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,18 @@ func loadCatalog(catalog *pb.ListProductsResponse) error {
3535
defer catalogMutex.Unlock()
3636

3737
if os.Getenv("ALLOYDB_CLUSTER_NAME") != "" {
38-
log.Info("Loading catalog from AlloyDB...")
3938
return loadCatalogFromAlloyDB(catalog)
4039
}
4140

42-
log.Info("Loading catalog from local products.json file...")
4341
return loadCatalogFromLocalFile(catalog)
4442
}
4543

4644
func loadCatalogFromLocalFile(catalog *pb.ListProductsResponse) error {
45+
log.Info("loading catalog from local products.json file...")
46+
4747
catalogJSON, err := os.ReadFile("products.json")
4848
if err != nil {
49-
log.Fatalf("failed to open product catalog json file: %v", err)
49+
log.Warnf("failed to open product catalog json file: %v", err)
5050
return err
5151
}
5252

@@ -63,6 +63,7 @@ func getSecretPayload(project, secret, version string) (string, error) {
6363
ctx := context.Background()
6464
client, err := secretmanager.NewClient(ctx)
6565
if err != nil {
66+
log.Warnf("failed to create SecretManager client: %v", err)
6667
return "", err
6768
}
6869
defer client.Close()
@@ -74,13 +75,16 @@ func getSecretPayload(project, secret, version string) (string, error) {
7475
// Call the API.
7576
result, err := client.AccessSecretVersion(ctx, req)
7677
if err != nil {
78+
log.Warnf("failed to access SecretVersion: %v", err)
7779
return "", err
7880
}
7981

8082
return string(result.Payload.Data), nil
8183
}
8284

8385
func loadCatalogFromAlloyDB(catalog *pb.ListProductsResponse) error {
86+
log.Info("loading catalog from AlloyDB...")
87+
8488
projectID := os.Getenv("PROJECT_ID")
8589
region := os.Getenv("REGION")
8690
pgClusterName := os.Getenv("ALLOYDB_CLUSTER_NAME")
@@ -96,6 +100,7 @@ func loadCatalogFromAlloyDB(catalog *pb.ListProductsResponse) error {
96100

97101
dialer, err := alloydbconn.NewDialer(context.Background())
98102
if err != nil {
103+
log.Warnf("failed to set-up dialer connection: %v", err)
99104
return err
100105
}
101106
cleanup := func() error { return dialer.Close() }
@@ -108,6 +113,7 @@ func loadCatalogFromAlloyDB(catalog *pb.ListProductsResponse) error {
108113

109114
config, err := pgxpool.ParseConfig(dsn)
110115
if err != nil {
116+
log.Warnf("failed to parse DSN config: %v", err)
111117
return err
112118
}
113119

@@ -118,13 +124,15 @@ func loadCatalogFromAlloyDB(catalog *pb.ListProductsResponse) error {
118124

119125
pool, err := pgxpool.NewWithConfig(context.Background(), config)
120126
if err != nil {
127+
log.Warnf("failed to set-up pgx pool: %v", err)
121128
return err
122129
}
123130
defer pool.Close()
124131

125132
query := "SELECT id, name, description, picture, price_usd_currency_code, price_usd_units, price_usd_nanos, categories FROM " + pgTableName
126133
rows, err := pool.Query(context.Background(), query)
127134
if err != nil {
135+
log.Warnf("failed to query database: %v", err)
128136
return err
129137
}
130138
defer rows.Close()
@@ -139,6 +147,7 @@ func loadCatalogFromAlloyDB(catalog *pb.ListProductsResponse) error {
139147
&product.Picture, &product.PriceUsd.CurrencyCode, &product.PriceUsd.Units,
140148
&product.PriceUsd.Nanos, &categories)
141149
if err != nil {
150+
log.Warnf("failed to scan query result row: %v", err)
142151
return err
143152
}
144153
categories = strings.ToLower(categories)
@@ -147,5 +156,6 @@ func loadCatalogFromAlloyDB(catalog *pb.ListProductsResponse) error {
147156
catalog.Products = append(catalog.Products, product)
148157
}
149158

159+
log.Info("successfully parsed product catalog from AlloyDB")
150160
return nil
151161
}

src/productcatalogservice/go.mod

+16-18
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.22
55
require (
66
cloud.google.com/go/alloydbconn v1.11.1
77
cloud.google.com/go/profiler v0.4.1
8-
cloud.google.com/go/secretmanager v1.13.5
8+
cloud.google.com/go/secretmanager v1.13.6
99
github.com/golang/protobuf v1.5.4
1010
github.com/jackc/pgx/v5 v5.6.0
1111
github.com/pkg/errors v0.9.1
@@ -14,26 +14,25 @@ require (
1414
go.opentelemetry.io/otel v1.28.0
1515
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0
1616
go.opentelemetry.io/otel/sdk v1.28.0
17-
golang.org/x/net v0.27.0
17+
golang.org/x/net v0.28.0
1818
google.golang.org/grpc v1.65.0
1919
)
2020

2121
require (
2222
cloud.google.com/go v0.115.0 // indirect
2323
cloud.google.com/go/alloydb v1.10.4 // indirect
24-
cloud.google.com/go/auth v0.7.2 // indirect
24+
cloud.google.com/go/auth v0.8.0 // indirect
2525
cloud.google.com/go/auth/oauth2adapt v0.2.3 // indirect
26-
cloud.google.com/go/compute v1.27.2 // indirect
2726
cloud.google.com/go/compute/metadata v0.5.0 // indirect
28-
cloud.google.com/go/iam v1.1.10 // indirect
29-
cloud.google.com/go/longrunning v0.5.9 // indirect
27+
cloud.google.com/go/iam v1.1.12 // indirect
28+
cloud.google.com/go/longrunning v0.5.11 // indirect
3029
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
3130
github.com/felixge/httpsnoop v1.0.4 // indirect
3231
github.com/go-logr/logr v1.4.2 // indirect
3332
github.com/go-logr/stdr v1.2.2 // indirect
3433
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
3534
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba // indirect
36-
github.com/google/s2a-go v0.1.7 // indirect
35+
github.com/google/s2a-go v0.1.8 // indirect
3736
github.com/google/uuid v1.6.0 // indirect
3837
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
3938
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
@@ -47,16 +46,15 @@ require (
4746
go.opentelemetry.io/otel/metric v1.28.0 // indirect
4847
go.opentelemetry.io/otel/trace v1.28.0 // indirect
4948
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
50-
golang.org/x/crypto v0.25.0 // indirect
51-
golang.org/x/oauth2 v0.21.0 // indirect
52-
golang.org/x/sync v0.7.0 // indirect
53-
golang.org/x/sys v0.22.0 // indirect
54-
golang.org/x/text v0.16.0 // indirect
55-
golang.org/x/time v0.5.0 // indirect
56-
google.golang.org/api v0.189.0 // indirect
57-
google.golang.org/appengine v1.6.8 // indirect
58-
google.golang.org/genproto v0.0.0-20240722135656-d784300faade // indirect
59-
google.golang.org/genproto/googleapis/api v0.0.0-20240722135656-d784300faade // indirect
60-
google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade // indirect
49+
golang.org/x/crypto v0.26.0 // indirect
50+
golang.org/x/oauth2 v0.22.0 // indirect
51+
golang.org/x/sync v0.8.0 // indirect
52+
golang.org/x/sys v0.23.0 // indirect
53+
golang.org/x/text v0.17.0 // indirect
54+
golang.org/x/time v0.6.0 // indirect
55+
google.golang.org/api v0.191.0 // indirect
56+
google.golang.org/genproto v0.0.0-20240730163845-b1a4ccb954bf // indirect
57+
google.golang.org/genproto/googleapis/api v0.0.0-20240725223205-93522f1f2a9f // indirect
58+
google.golang.org/genproto/googleapis/rpc v0.0.0-20240730163845-b1a4ccb954bf // indirect
6159
google.golang.org/protobuf v1.34.2 // indirect
6260
)

0 commit comments

Comments
 (0)