|
| 1 | +--- |
| 2 | +title: How to use gRPC in Azure Spring Apps |
| 3 | +description: Shows you how to use gRPC in Azure Spring Apps. |
| 4 | +author: KarlErickson |
| 5 | +ms.author: caihuarui |
| 6 | +ms.service: spring-apps |
| 7 | +ms.topic: how-to |
| 8 | +ms.date: 5/24/2023 |
| 9 | +ms.custom: devx-track-java |
| 10 | +--- |
| 11 | + |
| 12 | +# How to use gRPC in Azure Spring Apps |
| 13 | + |
| 14 | +> [!NOTE] |
| 15 | +> Azure Spring Apps is the new name for the Azure Spring Cloud service. Although the service has a new name, you'll see the old name in some places for a while as we work to update assets such as screenshots, videos, and diagrams. |
| 16 | +
|
| 17 | +**This article applies to:** ✔️ Basic/Standard ✔️ Enterprise |
| 18 | + |
| 19 | +This article shows you how to use gRPC in Azure Spring Apps. |
| 20 | + |
| 21 | +In this article, you modify and redeploy the [Spring Boot Pet Clinic](https://github.com/Azure-Samples/spring-petclinic-microservices) sample application. From your local environment, you create a gRPC service by modifying the `customers-service` microservice, deploy the modified sample to Azure Spring Apps, and then use `grpcurl` commands to test the service by making calls to gRPC methods. |
| 22 | + |
| 23 | +For a demonstration of this process, see the following video: |
| 24 | + |
| 25 | +<br> |
| 26 | + |
| 27 | +> [!VIDEO https://www.youtube.com/embed/yNvoQ4YIDCI] |
| 28 | +
|
| 29 | +## Prerequisites |
| 30 | + |
| 31 | +- An Azure subscription. If you don't have a subscription, create a [free account](https://azure.microsoft.com/free/) before you begin. |
| 32 | +- [Azure CLI](/cli/azure/install-azure-cli). |
| 33 | + - Use the following command to install the Azure Spring Apps extension: `az extension add --name spring` |
| 34 | +- [Git](https://git-scm.com/downloads). |
| 35 | +- [Microsoft Build of OpenJDK](/java/openjdk/download#openjdk-17) Version 17. |
| 36 | +- [Maven](https://maven.apache.org/download.cgi). |
| 37 | +- An Azure Spring Apps instance. For more information, see [Quickstart: Provision an Azure Spring Apps service instance](quickstart-provision-service-instance.md). |
| 38 | +- A built and deployed Pet Clinic sample application. For more information, see [Quickstart: Build and deploy apps to Azure Spring Apps](quickstart-deploy-apps.md). |
| 39 | + |
| 40 | +## Assign a public endpoint |
| 41 | + |
| 42 | +To facilitate testing, assign a public endpoint. The public endpoint is used in the `grpcurl` commands as the hostname. For more information, see [fullstorydev/grpcurl](https://github.com/fullstorydev/grpcurl). |
| 43 | + |
| 44 | +Use the following command to assign a public endpoint. Be sure to replace the placeholders with the resource group name, service instance name, and app name that you used when you fulfilled the prerequisites. |
| 45 | + |
| 46 | +```azurecli |
| 47 | +az spring app update \ |
| 48 | + --resource-group <resource-group-name> \ |
| 49 | + --service <Azure-Spring-Apps-instance-name> \ |
| 50 | + --name <app-name> \ |
| 51 | + --assign-public-endpoint true |
| 52 | +``` |
| 53 | + |
| 54 | +You can also use the Azure portal to assign a public endpoint. For more information, see [Expose applications on Azure Spring Apps to the internet from a public network](how-to-access-app-from-internet-virtual-network.md). |
| 55 | + |
| 56 | +## Modify an existing service to be a gRPC service |
| 57 | + |
| 58 | +Before the service is changed into a gRPC server, look at the Owners page of the deployed PetClinic instance application to examine the current pet owners data. You can also list all owners by adding `/owners` to the URL path, which you can get from the Overview page for the `customers-service` page in the Azure portal. |
| 59 | + |
| 60 | +Use the following steps to change `customers-service` into a gRPC server: |
| 61 | + |
| 62 | +1. Locate *pom.xml* in the *spring-petclinic-customers-service* folder. |
| 63 | + |
| 64 | +1. In the *pom.xml* file, delete the following element that defines the `spring-boot-starter-web` dependency: |
| 65 | + |
| 66 | + ```xml |
| 67 | + <dependency> |
| 68 | + <groupId>org.springframework.boot</groupId> |
| 69 | + <artifactId>spring-boot-starter-web</artifactId> |
| 70 | + </dependency> |
| 71 | + ``` |
| 72 | + |
| 73 | + If you don't remove this dependency, the application starts both a web server and a gRPC server. Azure Spring Apps then rewrites the server port to 1025, which prevents gRPC from being routed correctly with a static server address. |
| 74 | + |
| 75 | +1. Add the following elements to the *pom.xml* file. These elements define the dependency and build plugins required for gRPC. |
| 76 | + |
| 77 | + ```xml |
| 78 | + <dependencies> |
| 79 | + <!-- For both gRPC server and client --> |
| 80 | + <dependency> |
| 81 | + <groupId>net.devh</groupId> |
| 82 | + <artifactId>grpc-spring-boot-starter</artifactId> |
| 83 | + <version>2.5.1.RELEASE</version> |
| 84 | + <exclusions> |
| 85 | + <exclusion> |
| 86 | + <groupId>io.grpc</groupId> |
| 87 | + <artifactId>grpc-netty-shaded</artifactId> |
| 88 | + </exclusion> |
| 89 | + </exclusions> |
| 90 | + </dependency> |
| 91 | + <!-- For the gRPC server (only) --> |
| 92 | + <dependency> |
| 93 | + <groupId>net.devh</groupId> |
| 94 | + <artifactId>grpc-server-spring-boot-starter</artifactId> |
| 95 | + <version>2.5.1.RELEASE</version> |
| 96 | + <exclusions> |
| 97 | + <exclusion> |
| 98 | + <groupId>io.grpc</groupId> |
| 99 | + <artifactId>grpc-netty-shaded</artifactId> |
| 100 | + </exclusion> |
| 101 | + </exclusions> |
| 102 | + </dependency> |
| 103 | + <dependency> |
| 104 | + <groupId>net.devh</groupId> |
| 105 | + <artifactId>grpc-client-spring-boot-autoconfigure</artifactId> |
| 106 | + <version>2.5.1.RELEASE</version> |
| 107 | + <type>pom</type> |
| 108 | + </dependency> |
| 109 | + </dependencies> |
| 110 | + <build> |
| 111 | + <extensions> |
| 112 | + <extension> |
| 113 | + <groupId>kr.motd.maven</groupId> |
| 114 | + <artifactId>os-maven-plugin</artifactId> |
| 115 | + <version>1.6.1</version> |
| 116 | + </extension> |
| 117 | + </extensions> |
| 118 | + <plugins> |
| 119 | + <plugin> |
| 120 | + <groupId>org.springframework.boot</groupId> |
| 121 | + <artifactId>spring-boot-maven-plugin</artifactId> |
| 122 | + </plugin> |
| 123 | + <plugin> |
| 124 | + <groupId>org.xolstice.maven.plugins</groupId> |
| 125 | + <artifactId>protobuf-maven-plugin</artifactId> |
| 126 | + <version>0.6.1</version> |
| 127 | + <configuration> |
| 128 | + <protocArtifact> |
| 129 | + com.google.protobuf:protoc:3.3.0:exe:${os.detected.lassifier} |
| 130 | + </protocArtifact> |
| 131 | + <pluginId>grpc-java</pluginId> |
| 132 | + <pluginArtifact> |
| 133 | + io.grpc:protoc-gen-grpc-java:1.4.0:exe:${os.detected.classifier} |
| 134 | + </pluginArtifact> |
| 135 | + </configuration> |
| 136 | + <executions> |
| 137 | + <execution> |
| 138 | + <goals> |
| 139 | + <goal>compile</goal> |
| 140 | + <goal>compile-custom</goal> |
| 141 | + </goals> |
| 142 | + </execution> |
| 143 | + </executions> |
| 144 | + </plugin> |
| 145 | + </plugins> |
| 146 | + </build> |
| 147 | + ``` |
| 148 | + |
| 149 | +## Build the gRPC service |
| 150 | + |
| 151 | +Use the following steps to create and run a *.proto* file that defines the message types and RPC interface methods: |
| 152 | + |
| 153 | +1. Create a new file with the *.proto* extension in the source code folder that has the following content: |
| 154 | + |
| 155 | + ```protobuf |
| 156 | + syntax = "proto3"; |
| 157 | + option java_multiple_files = true; |
| 158 | + package org.springframework.samples.petclinic.customers.grpc; |
| 159 | + import "google/protobuf/empty.proto"; |
| 160 | +
|
| 161 | + message OwnerRequest { |
| 162 | + int32 ownerId = 1; |
| 163 | + } |
| 164 | +
|
| 165 | + message PetRequest { |
| 166 | + int32 petId = 1; |
| 167 | + } |
| 168 | +
|
| 169 | + message OwnerResponse { |
| 170 | + int32 id = 1; |
| 171 | + string firstName = 2; |
| 172 | + string lastName = 3; |
| 173 | + string address = 4; |
| 174 | + string city = 5; |
| 175 | + string telephone = 6; |
| 176 | + repeated PetResponse pets = 7; |
| 177 | + } |
| 178 | +
|
| 179 | + message PetResponse { |
| 180 | + int32 id = 1; |
| 181 | + string name = 2; |
| 182 | + string birthDate = 3; |
| 183 | + PetType type = 4; |
| 184 | + OwnerResponse owner = 5; |
| 185 | + } |
| 186 | +
|
| 187 | + message PetType { |
| 188 | + int32 id = 1; |
| 189 | + string name = 2; |
| 190 | + } |
| 191 | +
|
| 192 | + message PetTypes { |
| 193 | + repeated PetType ele = 1; |
| 194 | + } |
| 195 | +
|
| 196 | + message Owners { |
| 197 | + repeated OwnerResponse ele = 1; |
| 198 | + } |
| 199 | +
|
| 200 | + service CustomersService { |
| 201 | + rpc createOwner(OwnerResponse) returns (OwnerResponse); |
| 202 | + rpc findOwner(OwnerRequest) returns (OwnerResponse); |
| 203 | + rpc findAll(google.protobuf.Empty) returns (Owners); |
| 204 | + rpc updateOwner(OwnerResponse) returns (google.protobuf.Empty); |
| 205 | + rpc getPetTypes(google.protobuf.Empty) returns (PetTypes); |
| 206 | + rpc createPet(PetResponse) returns (PetResponse); |
| 207 | + rpc updatePet(PetResponse) returns (google.protobuf.Empty); |
| 208 | + rpc findPet(PetRequest) returns (PetResponse); |
| 209 | + } |
| 210 | + ``` |
| 211 | + |
| 212 | +1. Use the following command to generate the gRPC service files: |
| 213 | + |
| 214 | + ```bash |
| 215 | + mvn package |
| 216 | + ``` |
| 217 | + |
| 218 | + You can implement the gRPC service with the RPC methods defined in the *.proto* file. In the sample application, the generated files include *CustomersServiceGrpc.java*, as defined by the gRPC `proto` plugin. |
| 219 | + |
| 220 | +## Implement the gRPC service |
| 221 | + |
| 222 | +In your development environment, create a Java class file for the project with the following content that implements the RPC methods defined in the *.proto* file. Use the annotation `@GrpcService` to extend the autogenerated gRPC service base class to implement its methods. The following example shows an implementation of some of the methods: |
| 223 | + |
| 224 | +```java |
| 225 | +@GrpcService |
| 226 | +@Slf4j |
| 227 | +public class CustomersServiceImpl extends CustomersServiceGrpc.CustomersServiceImplBase { |
| 228 | + @Autowired |
| 229 | + private OwnerRepository ownerRepository; |
| 230 | + |
| 231 | + @Autowired |
| 232 | + private PetRepository petRepository; |
| 233 | + |
| 234 | + @Override |
| 235 | + public void createOwner(OwnerResponse request, StreamObserver<OwnerResponse> responseObserver) { |
| 236 | + Owner owner = new Owner(); |
| 237 | + BeanUtils.copyProperties(request, owner); |
| 238 | + ownerRepository.save(owner); |
| 239 | + |
| 240 | + responseObserver.onNext(request); |
| 241 | + responseObserver.onCompleted(); |
| 242 | + } |
| 243 | +} |
| 244 | +``` |
| 245 | + |
| 246 | +## Configure the server port to 1025 |
| 247 | + |
| 248 | +Next, configure the server port to 1025 so that the ingress rule works correctly. Add the following line to the *application.properties* file in the *spring-petclinic-customers-service/src/main/resources* folder. |
| 249 | + |
| 250 | +```properties |
| 251 | +grpc.server.port=1025 |
| 252 | +``` |
| 253 | + |
| 254 | +## Build the service JAR file |
| 255 | + |
| 256 | +Use the following command to build the gRPC server JAR file: |
| 257 | + |
| 258 | +```bash |
| 259 | +mvn package |
| 260 | +``` |
| 261 | + |
| 262 | +The modification of `customers-service` is now complete, and it's now a gRPC service. |
| 263 | + |
| 264 | +## Deploy the application to Azure Spring Apps |
| 265 | + |
| 266 | +You can now configure the server and deploy the application. |
| 267 | + |
| 268 | +Use the following command to deploy the newly built JAR file to your Azure Spring Apps instance. |
| 269 | + |
| 270 | +```azurecli |
| 271 | +az spring app deploy \ |
| 272 | + --name ${CUSTOMERS_SERVICE} \ |
| 273 | + --jar-path ${CUSTOMERS_SERVICE_JAR} \ |
| 274 | + --jvm-options='-Xms2048m -Xmx2048m -Dspring.profiles.active=mysql' \ |
| 275 | + --env MYSQL_SERVER_FULL_NAME=${MYSQL_SERVER_FULL_NAME} \ |
| 276 | + MYSQL_DATABASE_NAME=${MYSQL_DATABASE_NAME} \ |
| 277 | + MYSQL_SERVER_ADMIN_LOGIN_NAME=${MYSQL_SERVER_ADMIN_LOGIN_NAME} \ |
| 278 | + MYSQL_SERVER_ADMIN_PASSWORD=${MYSQL_SERVER_ADMIN_PASSWORD} |
| 279 | +``` |
| 280 | + |
| 281 | +The deployment can take a few minutes to complete. |
| 282 | + |
| 283 | +Now that the application is deployed in Azure Spring Apps, call a gRPC service from outside the Azure Spring Apps service instance. As you did earlier, test the `customers-service` endpoint to attempt to list all pet owners by adding `/owners` to the URL path. This time, the test fails as expected because a gRPC service can't be accessed using the HTTP protocol. |
| 284 | + |
| 285 | +## Set the ingress configuration |
| 286 | + |
| 287 | +Set the backend protocol to use gRPC so that you can use `grpcurl` commands to test the gRPC server. Update your application's ingress settings. For more information, see [Customize the ingress configuration in Azure Spring Apps](how-to-configure-ingress.md). |
| 288 | + |
| 289 | +## Call the sample application from a local environment |
| 290 | + |
| 291 | +You can use `grpcurl` to test the gRPC server. The only port supported for gRPC calls from outside Azure Spring Apps is port `443`. The traffic is automatically routed to port 1025 on the backend. |
| 292 | + |
| 293 | +Use the following `grpcurl` commands to check the gRPC server by listing all the pet owners. |
| 294 | + |
| 295 | +```bash |
| 296 | +grpcurl <service-instance-name>-customers-service.azuremicroservices.io:443 list |
| 297 | +grpcurl <service-instance-name>-customers-service.azuremicroservices.io:443 org.springframework.samples.petclinic.customers.grpc.CustomersService.findAll |
| 298 | +grpcurl -d "{\"ownerId\":7}" <service-instance-name>-customers-service.azuremicroservices.io:443 org.springframework.samples.petclinic.customers.grpc.CustomersService.findOwner |
| 299 | +``` |
| 300 | + |
| 301 | +## Frequently asked questions |
| 302 | + |
| 303 | +- How do I use the test endpoint? |
| 304 | + |
| 305 | + Use the following `curl` and HTTP commands to use the test endpoint of the gRPC server: |
| 306 | + |
| 307 | + ```bash |
| 308 | + echo -n '0000000000' | xxd -r -p - frame.bin |
| 309 | + curl -v --insecure --raw -X POST -H "Content-Type: application/grpc" -H "TE: trailers" --data-binary @frame.bin <test-endpoint/org. springframework.samples.petclinic.customers.grpc.CustomersService/findAll |
| 310 | + ``` |
| 311 | + |
| 312 | + For more information, see the [View apps and deployments](how-to-staging-environment.md#view-apps-and-deployments) section of [Set up a staging environment in Azure Spring Apps](how-to-staging-environment.md). |
| 313 | + |
| 314 | +## Next steps |
| 315 | + |
| 316 | +- [Customize the ingress configuration in Azure Spring Apps](how-to-configure-ingress.md) |
0 commit comments