The AWS team recently launched end-to-end support for HTTP/2 on Application Load Balancers, as announced on their blog. This is great news if you want to upgrade your stack to use modern tooling like gRPC. The AWS team has also published a post on how to setup and deploy a gRPC application on ECS, using the Fargate launch type. This post aims to explain how to achieve the same using the EC2 launch type.
The Problem
Normally, you might directly go ahead and create a service from the ECS console. This will automatically create a target group for you. But unfortunately, the automatic target group creation does not seem to support gRPC (at least as of Nov 1st 2020). Hence, this blog post.
The tl;dr Solution
So instead, we have to follow this flow:
1. Create Target Group first, with the gRPC protocol
2. Setup the routing in your ALB to let the traffic flow into your target group
3. Create Service using this newly created Target Group
The step-by-step Solution
Note: In this post, I will be using golang for the service and client. However, it should be applicable no matter what language you are using for your gRPC service.
I will be using a modified version of the Greeter service example from the grpc-go repository. Complete version of the modified code can be found on my Github: https://github.com/chaitan94/grpc-on-ecs
git clone https://github.com/chaitan94/grpc-on-ecs.git
cd grpc-on-ecs
To follow-along with the step-by-step solution, clone the repo, and follow these steps:
Step 1: Build the service as a docker image
Generating the stubs
cd greeter_server
# We need to generate the gRPC stubs.
# Before doing that, make sure you have these installed first:
# - protoc
# - protoc-gen-go
# - protoc-gen-go-grpc
protoc --go_out=./gen --go_opt=paths=source_relative \
--go-grpc_out=./gen --go-grpc_opt=paths=source_relative \
-I../helloworld helloworld.proto
# Building the server as a docker image
docker build -t greeter_server .
(Optional) Step 1.5: Testing locally
Run the server image locally:
docker run -it --name greeter_server -p 50051:50051 greeter_server
While the server is running, in a separate terminal, run the client:
cd client
go run main.go
If you can see the message Greeting: Hello world
, you ran everything successfully! :)
Step 2: Deploy the server image to ECR
- Create an ECR repository, say with the name 'greeter_server'
- Push your image to ECR (modify accordingly to match your AWS region and ECR repo tag)
$(aws ecr get-login --no-include-email --region ap-south-1)
docker tag greeter_server 123123123123.dkr.ecr.ap-south-1.amazonaws.com/greeter_server:latest
docker push 123123123123.dkr.ecr.ap-south-1.amazonaws.com/greeter_server:latest
Step 3: Create a new Task Definition
- Select EC2 as the Launch type, and select Next step.
- Provide a Task Definition Name, such as greeter_server.
- Provide the Task Memory and CPU (0.5 GB memory and 0.25 vCPU is sufficient).
- To add a container to the task, select Add container and provide the following parameters:
- Container name: greeter_server
- Image: 123123123123.dkr.ecr.ap-south-1.amazonaws.com/greeter_server:latest
- Memory Limits (MiB): Soft Limit, 128
- Port mappings: Host port: 0, Container port: 50051, Protocol: tcp
- Choose Add.
- Navigate to the bottom of the page and choose Create.
Step 4: Setting up the target group and load balancer
As explained above, we need to create target group manually, otherwise your ECS service won't work over the gRPC protocol.
- Create Target Group
- Go to EC2 console -> Target groups.
- Click Create Target Group.
- Provide a Target Group Name, such as greeter-server.
- Leave Protocol and Port to the default values, i.e., "HTTP" and "80".
- Set Protocol version to "gRPC". (Note: this is different from the protocol we selected in the previous step)
- In health checks section, set Health check path to "/helloworld.Greeter/".
- Click Next.
- In the next step, no need to register any targets as ECS would do that for us. Proceed to click "Create target group".
- Setup your load balancer to receive traffic and forward it to your newly created target group.
- Go to your ALB's Listeners tab.
- Assuming you are using a HTTPS listener, Click View/edit rules, for the listener "HTTPS : 443". (Note: HTTP listener is not supported by AWS ALB for forwarding gRPC traffic right now.)
- Click the plus icon to add a new rule.
- Click Insert rule at an appropriate location.
- Add a path condition with path value = "/helloworld.Greeter*" and an action to forward to the target group "greeter-server".
- Click Save.
Step 5: Creating the Service
- If you don't have a cluster yet, create one.
- In your cluster, under the Services tab, click Create.
- Select EC2 as the Launch type.
- Select the Task Definition Family and Revision from the previous step.
- Provide a Service name, such as greeter_server.
- Set the Number of tasks to 1.
- Choose Next step.
- Create a new security group. (or select an existing one, if you already have one. Make sure 50051 port is allowed in the inbound rules.
- Choose Edit next to Security groups.
- For Inbound rules for security group, change the Type to Custom TCP and set the Port range to 50051. (Note: This is a bad security posture and only permissible for this demo. Your application should have more strict security rules.)
- Choose Save.
- In the Load Balancing section, select your Application Load Balancer
- Ensure that "greeter_service:0:50051" is selected, and Click Add to Load Balancer
- In Production listener port, Select "443:HTTPS".
- Under Target group name, select the target group created in the previous step. i.e, "greeter-server"
- Choose Next step.
- Choose Next step again to skip auto scaling.
- Choose Create Service to launch the service.
Step 6: Verify your deployment
You can verify that your service is running properly by connecting to it using the client.
cd client
GREETER_ENDPOINT=mydomain.com:443 INSECURE=0 go run main.go
If you can see the message Greeting: Hello world
, you ran everything successfully! :)
Note: Here I am assuming you have your domain called mydomain.com mapped to your ALB. You can also use your ALB's hostname directly. If you do not use HTTPS, you can ignore the INSECURE flag while running.
And that's it. I hope this post helped you in any way!
Feel free to DM me on twitter if you have any feedback or questions :)
Top comments (0)