implementation("io.micronaut.gcp:micronaut-gcp-common:2.0.0.M3")
Micronaut GCP
Provides integration between Micronaut and Google Cloud Platform (GCP)
Version:
1 Introduction
This project provides various extensions to Micronaut to integrate Micronaut with Google Cloud Platform (GCP).
2 Setting up GCP Support
The micronaut-gcp-common
module includes basic setup for running applications on Google Cloud.
<dependency>
<groupId>io.micronaut.gcp</groupId>
<artifactId>micronaut-gcp-common</artifactId>
<version>2.0.0.M3</version>
</dependency>
Prerequisites:
-
You should have a Google Cloud Platform project created
-
Configure default project
gcloud config set project YOUR_PROJECT_ID
-
Authenticate with
gcloud auth login
-
Authenticate application default credential with
gcloud auth application-default login
It’s strongly recommended that you use a Service Account for your application.
Google Project ID
The module features a base GoogleCloudConfiguration which you can use to configure or retrieve the GCP Project ID:
Property | Type | Description |
---|---|---|
|
java.lang.String |
Sets the project id to use. |
You can inject this bean and use the getProjectId()
method to retrieve the configured or detected project ID.
Google Credentials
The module will setup a bean of exposing the com.google.auth.oauth2.GoogleCredentials
instance that are either detected from the local environment or configured by GoogleCredentialsConfiguration:
Property | Type | Description |
---|---|---|
|
java.util.List |
The default scopes to associate with the application to access specific APIs. See <a href="https://developers.google.com/identity/protocols/googlescopes">Google Scopes</a> for a complete list. Leave this empty if you don’t need additional API access. |
|
java.lang.String |
Sets the Base64 encoded service account key content.. |
|
java.lang.String |
Sets the location to the service account credential key file. |
3 Stackdriver Trace
The micronaut-gcp-tracing
integrates Micronaut with Stackdriver Trace.
To enable it add the following dependency:
implementation("io.micronaut.gcp:micronaut-gcp-tracing:2.0.0.M3")
<dependency>
<groupId>io.micronaut.gcp</groupId>
<artifactId>micronaut-gcp-tracing</artifactId>
<version>2.0.0.M3</version>
</dependency>
Then enabling Zipkin tracing in your configuration application.yml
:
tracing:
zipkin:
enabled: true
# [Optional] Set sampling probability to 100% for dev/testing purposes to observe traces.
#
# sampler:
# probability=1.0
# [Optional] configuration to enable/disable Stackdriver Trace configuration.
# This is defaulted to true.
#
# gcp:
# tracing:
# enabled: true
4 Authorizing HTTP Clients
The micronaut-gcp-http-client
module can be used to help authorize service-to-service communication. To get started add the following module:
implementation("io.micronaut.gcp:micronaut-gcp-http-client")
<dependency>
<groupId>io.micronaut.gcp</groupId>
<artifactId>micronaut-gcp-http-client</artifactId>
</dependency>
You should then configure the service accounts as per the documentation on service-to-service communication and the enable the filter for the outgoing URI paths you wish to include the Google-signed OAuth ID token:
gcp:
http:
client:
auth:
patterns:
- /foo/**
- /bar/**
5 Cloud Function Support
Micronaut GCP includes extended support for Google Cloud Function - designed for serverless workloads.
5.1 Simple Functions
Micronaut GCP offers two ways to write cloud functions with Micronaut. The first way is more low level and involves using Micronaut’s built in support for functions. Simply add the following dependency to your classpath:
implementation("io.micronaut.gcp:micronaut-gcp-function")
<dependency>
<groupId>io.micronaut.gcp</groupId>
<artifactId>micronaut-gcp-function</artifactId>
</dependency>
Then add the Cloud Function API as a compileOnly
dependency (provided
with Maven):
compileOnly("com.google.cloud.functions:functions-framework-api:1.0.1")
<dependency>
<groupId>com.google.cloud.functions</groupId>
<artifactId>functions-framework-api</artifactId>
<version>1.0.1</version>
<scope>provided</scope>
</dependency>
Now define a class that implements one of Google Cloud Found’s interfaces, for example com.google.cloud.functions.BackgroundFunction
, and extends from io.micronaut.function.executor.FunctionInitializer
.
The following is an example of a BackgroundFunction
that uses Micronaut and Google Cloud Function:
/*
* Copyright 2017-2019 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.background;
import com.google.cloud.functions.*;
import io.micronaut.gcp.function.GoogleFunctionInitializer;
import javax.inject.*;
import java.util.*;
public class Example extends GoogleFunctionInitializer (1)
implements BackgroundFunction<PubSubMessage> { (2)
@Inject LoggingService loggingService; (3)
@Override
public void accept(PubSubMessage message, Context context) {
loggingService.logMessage(message);
}
}
class PubSubMessage {
String data;
Map<String, String> attributes;
String messageId;
String publishTime;
}
@Singleton
class LoggingService {
void logMessage(PubSubMessage message) {
// log the message
}
}
/*
* Copyright 2017-2019 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.background
import com.google.cloud.functions.*
import io.micronaut.gcp.function.GoogleFunctionInitializer
import javax.inject.*
class Example extends GoogleFunctionInitializer (1)
implements BackgroundFunction<PubSubMessage> { (2)
@Inject LoggingService loggingService (3)
@Override
void accept(PubSubMessage message, Context context) {
loggingService.logMessage(message)
}
}
class PubSubMessage {
String data
Map<String, String> attributes
String messageId
String publishTime
}
@Singleton
class LoggingService {
void logMessage(PubSubMessage message) {
// log the message
}
}
/*
* Copyright 2017-2019 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.background
import com.google.cloud.functions.BackgroundFunction
import com.google.cloud.functions.Context
import io.micronaut.gcp.function.GoogleFunctionInitializer
import javax.inject.Inject
import javax.inject.Singleton
class Example : GoogleFunctionInitializer(), (1)
BackgroundFunction<PubSubMessage> { (2)
@Inject
lateinit var loggingService: LoggingService (3)
override fun accept(message: PubSubMessage, context: Context) {
loggingService.logMessage(message)
}
}
class PubSubMessage {
var data: String? = null
var attributes: Map<String, String>? = null
var messageId: String? = null
var publishTime: String? = null
}
@Singleton
class LoggingService {
fun logMessage(message: PubSubMessage) {
// log the message
}
}
1 | The function extends from io.micronaut.function.executor.FunctionInitializer |
2 | The function implements com.google.cloud.functions.BackgroundFunction |
3 | Dependency injection can be used on the fields |
When you extend from FunctionInitializer
the Micronaut ApplicationContext
will be initialized and dependency injection will be performed on the function instance. You can use inject any bean using javax.inject.Inject
as usual.
Functions require a no argument constructor hence you must use field injection (which requires lateinit in Kotlin) when injecting dependencies into the function itself.
|
The FunctionInitializer
super class provides numerous methods that you can override to customize how the ApplicationContext
is built if desired.
5.2 HTTP Functions
It is common to want to take just a slice of a regular Micronaut HTTP server application and deploy it as a function.
Configuration
To facilitate this model, Micronaut GCP includes an additional module that allows you to use regular Micronaut annotations like @Controller
and @Get
to define your functions that can be deployed to cloud function.
With this model you need to add the micronaut-gcp-function-http
dependency to your application:
implementation("io.micronaut.gcp:micronaut-gcp-function-http:2.0.0.M3")
<dependency>
<groupId>io.micronaut.gcp</groupId>
<artifactId>micronaut-gcp-function-http</artifactId>
<version>2.0.0.M3</version>
</dependency>
And define the Google Function API as a development only dependency:
developmentOnly("com.google.cloud.functions:functions-framework-api:1.0.1")
<dependency>
<groupId>com.google.cloud.functions</groupId>
<artifactId>functions-framework-api</artifactId>
<version>1.0.1</version>
<scope>developmentOnly</scope>
</dependency>
Running Functions Locally
First to run the function locally you should then make the regular Micronaut server a developmentOnly
dependency since it is not necessary to include it in the JAR file that will be deployed to Cloud Function:
developmentOnly("io.micronaut:micronaut-http-server-netty")
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-http-server-netty</artifactId>
<scope>developmentOnly</scope>
</dependency>
You can then use ./gradlew run
or ./mvnw compile exec:exec
to run the function locally using Micronaut’s Netty-based server.
Alternatively, you could configure the Google Function Framework for Java which includes a Maven plugin, or for Gradle include the following:
configurations {
invoker
}
dependencies {
invoker 'com.google.cloud.functions.invoker:java-function-invoker:1.0.0-alpha-2-rc3'
}
task('runFunction', type: JavaExec, dependsOn: classes) {
main = 'com.google.cloud.functions.invoker.runner.Invoker'
classpath(configurations.invoker)
args(
'--target', 'io.micronaut.gcp.function.http.HttpFunction',
'--classpath', (configurations.runtimeClasspath + sourceSets.main.output).asPath,
'--port', 8081
)
}
With this in place you can run ./gradlew runFunction
to run the function locally.
Deployment
When deploying the function to Cloud Function you should use the HttpFunction class as the handler reference.
First build the function with:
$ ./gradlew clean shadowJar
Then cd
into the build/libs
directory (deployment has to be done from the location where the JAR file resides):
$ cd build/libs
To deploy the function make sure you have gcloud
CLI then run:
$ gcloud alpha functions deploy myfunction --entry-point io.micronaut.gcp.function.http.HttpFunction --runtime java11 --trigger-http
In the example above myfunction
refers to the name of your function and can be changed to whatever name you prefer to name your function.
To obtain the trigger URL you can use the following command:
$ YOUR_HTTP_TRIGGER_URL=$(gcloud alpha functions describe myfunction --format='value(httpsTrigger.url)')
You can then use this variable to test the function invocation:
$ curl -i $YOUR_HTTP_TRIGGER_URL/hello/John