10 min read

Google Cloud Laundry List

Mallim

Notes from the Building Scalable Java Microservices with Spring Boot and Spring Cloud in Coursera

Table of Contents

JAVAMS01 Bootstrapping the Application Frontend and Backend

gcloud config list account
gcloud config list project

Set timezone

gcloud config set compute/zone [YOUR_ZONE]

Clone demo application

git clone https://github.com/saturnism/spring-cloud-gcp-guestbook.git

Use jq to parse the JSON return text.

curl -s http://localhost:8081/guestbookMessages \
  | jq -r '._embedded.guestbookMessages[] | {name: .name, message: .message}'

JAVAMS02 Configuring and Connecting to Cloud SQL

Cloning

Create an environment variable that contains the project ID for this lab

export PROJECT_ID=$(gcloud config list --format 'value(core.project)')

Verification

gsutil ls gs://$PROJECT_ID

Copy to Cloud Shell

gsutil -m cp -r gs://$PROJECT_ID/* ~/

Cloud SQL Administration

Enable Cloud SQL Administration API

gcloud services enable sqladmin.googleapis.com

Confirm that Cloud SQL Administration API is enabled

gcloud services list | grep sqladmin

List the Cloud SQL instances.

gcloud sql instances list

Create a Cloud SQL instance

Provision a new Cloud SQL instance.

gcloud sql instances create guestbook --region=us-central1

Create a messages database in the MySQL instance.

gcloud sql databases create messages --instance guestbook

Connect to Cloud SQL and create the schema

Temporarily whitelists the IP address for the connection.

gcloud sql connect guestbook

Find instance name for Java datasource configuration

gcloud sql instances describe guestbook --format='value(connectionName)'

Java dependancies

Maven dependancies

 <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-gcp-starter-sql-mysql</artifactId>
</dependency>

Spring Boot profile

spring.cloud.gcp.sql.enabled=false
spring.cloud.gcp.sql.database-name=messages
spring.cloud.gcp.sql.instance-connection-name=YOUR_INSTANCE_CONNECTION_NAME

JAVAMS03 Working with Runtime Configurations

Java Changes

Spring Cloud GCP Config starter

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-gcp-starter-config</artifactId>
</dependency>
<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>20.0</version>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Frontend needs bootstrap-cloud.properties

spring.cloud.gcp.config.enabled=true
spring.cloud.gcp.config.name=frontend
spring.cloud.gcp.config.profile=cloud

application.properties

management.endpoints.web.exposure.include=*

RefreshScope annotation

import org.springframework.cloud.context.config.annotation.RefreshScope;

@RefreshScope

Create a runtime configuration

Enable Cloud Runtime Configuration API.

gcloud services enable runtimeconfig.googleapis.com

Create a runtime configuration for the frontend application's cloud profile.

gcloud beta runtime-config configs create frontend_cloud

Set a new configuration value for the greeting message.

gcloud beta runtime-config configs variables set greeting \
  "Hi from Runtime Config" \
  --config-name frontend_cloud

Display all the variables in the runtime configuration:

gcloud beta runtime-config configs variables list --config-name=frontend_cloud

Display the value of a specific variable.

gcloud beta runtime-config configs variables \
  get-value greeting --config-name=frontend_cloud

JAVAMS04 Working with Stackdriver Trace

Enable Stackdriver Trace API

gcloud services enable cloudtrace.googleapis.com

Spring Cloud GCP Trace starter

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-gcp-starter-trace</artifactId>
</dependency>

Configure properties

application-cloud.properties

spring.cloud.gcp.trace.enabled=true
spring.sleuth.sampler.probability=1
spring.sleuth.web.skipPattern=(^cleanup.*|.+favicon.*)

Set up a service account

Create a service account specific to the guestbook application.

gcloud iam service-accounts create guestbook

Add the Editor role for your project to this service account.

export PROJECT_ID=$(gcloud config list --format 'value(core.project)')
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:guestbook@${PROJECT_ID}.iam.gserviceaccount.com \
  --role roles/editor

Generate the JSON key file to be used by the application to identify itself using the service account.

gcloud iam service-accounts keys create \
    ~/service-account.json \
    --iam-account guestbook@${PROJECT_ID}.iam.gserviceaccount.com

JAVAMS05 Messaging with Cloud Pub/Sub

Enable Cloud Pub/Sub API

gcloud services enable pubsub.googleapis.com

Create a Cloud Pub/Sub topic

gcloud pubsub topics create messages

Add Spring Cloud GCP Pub/Sub starter

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-gcp-starter-pubsub</artifactId>
</dependency>

Publish message in Java code

import org.springframework.cloud.gcp.pubsub.core.*;

@Autowired
private PubSubTemplate pubSubTemplate;

pubSubTemplate.publish("messages", name + ": " + message);

Create a subscription

Create a Cloud Pub/Sub subscription

gcloud pubsub subscriptions create messages-subscription-1 \
  --topic=messages

Pull messages from the subscription.

gcloud pubsub subscriptions pull messages-subscription-1

Remove message from the subscription by using the auto-acknowledgement switch

gcloud pubsub subscriptions pull messages-subscription-1 --auto-ack

JAVAMS06 Integrating Cloud Pub/Sub with Spring

Add the Spring Integration core

<dependency>
  <groupId>org.springframework.integration</groupId>
  <artifactId>spring-integration-core</artifactId>
</dependency>

Create an outbound message gateway

Add OutboundGateway.java in guestbook-frontend

package com.example.frontend;

import org.springframework.integration.annotation.MessagingGateway;

@MessagingGateway(defaultRequestChannel = "messagesOutputChannel")
public interface OutboundGateway {
        void publishMessage(String message);
}

Publish the message

@Autowired
private OutboundGateway outboundGateway;

...

 outboundGateway.publishMessage(name + ": " + message);

Bind the output channel to the Cloud Pub/Sub topic

@Bean
@ServiceActivator(inputChannel = "messagesOutputChannel")
public MessageHandler messageSender(PubSubTemplate pubsubTemplate) {
  return new PubSubMessageHandler(pubsubTemplate, "messages");
}

JAVAMS08 Using Cloud Platform APIs

Enable Vision API

gcloud services enable vision.googleapis.com

Add the Vision client library

<dependency>
  <groupId>com.google.cloud</groupId>
  <artifactId>google-cloud-vision</artifactId>
</dependency>

Add a GCP credential scope for Spring

application.properties

spring.cloud.gcp.credentials.scopes=https://www.googleapis.com/auth/cloud-platform

Create a Vision API client bean

import java.io.IOException;
import com.google.cloud.vision.v1.*;
import com.google.api.gax.core.CredentialsProvider;

// This configures the Vision API settings with a
// credential using the the scope we specified in
// the application.properties.
@Bean
public ImageAnnotatorSettings imageAnnotatorSettings(
  CredentialsProvider credentialsProvider)
                throws IOException {
  return ImageAnnotatorSettings.newBuilder()
      .setCredentialsProvider(credentialsProvider).build();
}

@Bean
public ImageAnnotatorClient imageAnnotatorClient(
                ImageAnnotatorSettings settings)
                throws IOException {
  return ImageAnnotatorClient.create(settings);
}

Analyze the image

import com.google.cloud.vision.v1.*;

    @Autowired
    private ImageAnnotatorClient annotatorClient;

    private void analyzeImage(String uri) {
        // After the image was written to GCS,
        // analyze it with the GCS URI.It's also
        // possible to analyze an image embedded in
        // the request as a Base64 encoded payload.
        List<AnnotateImageRequest> requests = new ArrayList<>();
        ImageSource imgSrc = ImageSource.newBuilder()
             .setGcsImageUri(uri).build();
        Image img = Image.newBuilder().setSource(imgSrc).build();
        Feature feature = Feature.newBuilder()
             .setType(Feature.Type.LABEL_DETECTION).build();
        AnnotateImageRequest request = AnnotateImageRequest
             .newBuilder()
             .addFeatures(feature)
             .setImage(img)
             .build();
        requests.add(request);
        BatchAnnotateImagesResponse responses =
              annotatorClient.batchAnnotateImages(requests);
           // We send in one image, expecting just
           // one response in batch
        AnnotateImageResponse response =responses.getResponses(0);
        System.out.println(response);
    }

Setup service account

export PROJECT_ID=$(gcloud config list --format 'value(core.project)')
gcloud iam service-accounts create guestbook

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:guestbook@${PROJECT_ID}.iam.gserviceaccount.com \
  --role roles/editor

gcloud iam service-accounts keys create \
    ~/service-account.json \
    --iam-account guestbook@${PROJECT_ID}.iam.gserviceaccount.com

JAVAMS09 Deploying to App Engine

Initialize App Engine

gcloud app create --region=us-central

Make the guestbook frontend App Engine friendly

<plugin>
  <groupId>com.google.cloud.tools</groupId>
  <artifactId>appengine-maven-plugin</artifactId>
  <version>1.3.1</version>
  <configuration>
    <version>1</version>
  </configuration>
</plugin>

appengine-web.xml

<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
  <service>default</service>
  <version>1</version>
  <threadsafe>true</threadsafe>
  <runtime>java8</runtime>
  <instance-class>B4_1G</instance-class>
  <sessions-enabled>true</sessions-enabled>
  <manual-scaling>
    <instances>2</instances>
  </manual-scaling>
  <system-properties>
    <property name="spring.profiles.active" value="cloud" />
  </system-properties>
</appengine-web-app>

Configure the frontend application to use the backend URL

gcloud beta runtime-config configs variables set messages.endpoint \
  "https://guestbook-service-dot-${PROJECT_ID}.appspot.com/guestbookMessages" \
  --config-name frontend_cloud

Deploy the frontend application to App Engine

./mvnw appengine:deploy -DskipTests

gcloud app browse

JAVAMS12 Deploying to Kubernetes Engine

Create a Kubernetes Engine cluster

Enable Kubernetes Engine API

gcloud services enable container.googleapis.com

Create a Kubernetes Engine cluster that has Cloud Logging and Monitoring enabled.

gcloud container clusters create guestbook-cluster \
    --zone=us-central1-a \
    --num-nodes=2 \
    --machine-type=n1-standard-2 \
    --enable-autorepair \
    --enable-cloud-monitoring \
    --enable-cloud-logging

Containerize the applications

Enable Container Registry API.

gcloud services enable containerregistry.googleapis.com

Set up a service account

Create a service account specific to the guestbook application.

gcloud iam service-accounts create guestbook

Add the Editor role for your project to this service account.

export PROJECT_ID=$(gcloud config list --format 'value(core.project)')
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:guestbook@${PROJECT_ID}.iam.gserviceaccount.com \
  --role roles/editor

Generate the JSON key file to be used by the application to identify itself using the service account.

gcloud iam service-accounts keys create \
    ~/service-account.json \
    --iam-account guestbook@${PROJECT_ID}.iam.gserviceaccount.com

Check the Kubernetes server version to verify that the Kubernetes Engine cluster

kubectl version

Create the secret using the service account credential file.

kubectl create secret generic guestbook-service-account \
  --from-file=$HOME/service-account.json

Verify that the service account is stored.

kubectl describe secret guestbook-service-account

Deploy the updated Kubernetes deployments.

kubectl apply -f ~/kubernetes/

Check the status of the frontend application deployment.

kubectl get svc guestbook-frontend

Check the status of all of the services running on your Kubernetes Engine cluster.

kubectl get svc

JAVAMS13 Working with Kubernetes Monitoring

Enable Cloud Monitoring and view the Cloud Kubernetes Monitoring dashboard

Fix for a runtime issue

<dependency>
  <groupId>javax.xml.bind</groupId>
  <artifactId>jaxb-api</artifactId>
  <version>2.3.1</version>
</dependency>
<dependency>
  <groupId>javassist</groupId>
  <artifactId>javassist</artifactId>
  <version>3.12.1.GA</version>
</dependency>

qwiklabs-gcp-04-d4caf43d907d