Set Up a gRPC Web Server With Aws
Intro
I was asked on one of my last posts about gRPC, how does one host a gRPC web server. I thought it would be a good opportunity to learn what the AWS customer experience is, currently, for setting up a simple gRPC web server. If you are advanced at gRPC and AWS already, you could probably set it up just using this post: https://aws.amazon.com/blogs/aws/new-application-load-balancer-support-for-end-to-end-http-2-and-grpc/, which is what I am using to do this. But if you need some guidance on how to use these components, like I did. The following may be helpful to you.
Setting up an EC2 instance
My first step is setting up an EC2 instance, which will run our gRPC web server. From the AWS console,
- select EC2.
- select “Instances”
- select “Launch Instances”
- Next, you can configure your EC2 instance. In case you are unfamiliar, here is what I did:
- Select Amazon Linux 2 AMI on 64-bit (x86)
- Choose t2.micro (Because it’s free)
- Click review and launch and then, on the next page launch
- Make sure that you add TCP on port 50051 as an open inbound port for your security group.
Set up an ALB for my EC2 instance
Technically, you already have a web server you could host your gRPC web application on, but I wanted to try setting up a load balancer as well.
- Click “Load Balancers” on the left
- Click “Create Load Balancer”
- Click “Application Load Balancer”
- Enter any name (I chose “test-alb”)
- Under Listeners, choose HTTPS and port 50051
- Under Availability Zones, select two AZs but make sure the one that your EC2 instance was created in is one of them. For me that was
us-west-2d
, but you can check on the EC2 console where yours is. - Click Configure Security Settings
Creating a certificate
This was one of the toughest parts for me, since I didn’t actually have a real certificate to use. Luckily, you can create a self-signed certificate and use it here just fine, but it requires a little extra work. Note this is not a best practice, but it will work for this little demo. First, on my computer I ran1:
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout example.key -out example.crt -subj "/CN=example.com" -addext "subjectAltName-DNS:example.com,DNS:www.example.net,IP:10.0.0.1"
Then I tried to use this certificate in various ways, by adding it in the Load Balancer creation UX with both ACM and IAM, and also adding it into ACM through the ACM UX and then trying to choose it here. Unfortunately, they all didn’t work for me. Instead what did work for me was importing it into IAM and choosing it here. This is not a best practice, but it’s what we’re doing here for convenience.
aws iam upload-server-certificate --server-certificate-name test-cert --certificate-body file://example.crt --private-key file://example.key
Then, I was able to find this certificate in the Load Balancer creation UX.
Load Balancer Creation Continued
- For Security groups, I just chose the security group my EC2 instance belonged in.
- For Configure Routing, I created a new target group (test-target-group)
- Choose Instance for target type
- Protocol: HTTPS
- Port 50051
- Protocol Version: gRPC
- Register targets: I chose my EC2 instance here.
- Click review and then create.
Running a gRPC server on the instance
Next, we want to start some gRPC server on port 50051 so we can do an end to end test.
I’m starting by running rustup so I can create a simple tonic server.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
cargo new server
cd server
Next, I open up Cargo.toml
and added tonic
and tonic-health
. e.g.
[dependencies]
tonic = "0.4"
tonic-health = "0.3.1"
tokio = { version = "1.5.0", features = ["full"] }
Then cargo build
. This failed for me because it was missing cc
, which is strange because it looks like glibc
is actually installed. But, I just ran sudo yum groupinstall "Development Tools"
which installs a collection of tools, and it worked after that.
Once that’s done, open up src/main.rs
and put in
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let (mut health_reporter, health_service) = tonic_health::server::health_reporter();
health_reporter
.set_service_status("".to_string(), tonic_health::ServingStatus::Serving)
.await;
let addr = "0.0.0.0:50051".parse().unwrap();
tonic::transport::Server::builder()
.add_service(health_service)
.serve(addr)
.await?;
Ok(())
}
Start your server with cargo run
Testing a request to the Load Balancer
If everything is set up correctly, you should now be able to use evans
to access your web server at the load balancer url or even the url for your ec2 instance directly e.g.
evans --host <your url> --proto health.proto -p 50051
You can get the health.proto file here: https://github.com/hyperium/tonic/blob/master/tonic-health/proto/health.proto
Conclusion
Hopefully, this will help other people who are interested in setting up a gRPC web server on AWS. There doesn’t seem to be a lot of documentation out there on this specifically, so I hope that this article will be useful.
-
This actually didn’t work for me on my macOS machine because the openssl typically in the path on macOS is actually LibreSSL. You should instead
brew install openssl
and use that binary’s absolute path. ↩︎