Skip to content

Commit e559dc2

Browse files
authored
Docker & Kubernetes (#1)
* added builder stage to the envoy proxy to create descriptior file * updated the dockerfile for the book service to remove references to hello. Updated the readme with some documentation. Updated docker-compose to change hello to books * minor improvements to the readme to explain which ports are exposed * fixed service dockerfile to reference the correct binary. Updated envoy to use the correct container name * created kubernetes deployment called books for deploying the books api and envoy sidecar * updated readme with details on how to run the books service locally and how to compile the protocol buffers * added the google api location to the makefile. Reduce the space identation on the docker-compose.yaml from 4 to 2 spaces * added comments to the books.proto file * added docs to books endpoint. Fixed docker-compose file * updated readme to reflect changes in folder structure. Updated envoy container to swap out yaml in the container * added kubernetes version of the envoy config * added a config map for kubernetes to maintain the envoy config. Added this configmap to the deployment spec * updated the envoy docker file to move the proto descriptor file into its own sub directory in ect. Fixed the kubernetes deployment to enable the volumne to work correctly. Removed envoy-kube.yaml file since this is managed in the config map * add docs on the readme about kubernetes * corrections to the readme for the kubernetes section
1 parent ce04057 commit e559dc2

14 files changed

+301
-53
lines changed

.dockerignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
googleapis/*
2-
hello

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,5 @@ Temporary Items
8888

8989
# Application files
9090
googleapis/*
91+
books-service
9192
protos/books.pb

Dockerfile.envoy

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
# Build stage
2-
# FROM alpine:3.7 as builder
3-
# WORKDIR /app/protoc/
4-
# COPY protos/* .
5-
# RUN apk update && \
6-
# apk add --no-cache protoc && \
7-
# apk add --no-cache wget
8-
# RUN wget https://github.com/googleapis/googleapis.git && \
9-
# protoc -I./googleapis -I. \
10-
# --include_imports \
11-
# --include_source_info \
12-
# --descriptor_set_out=envoy/books.pb protos/books.proto
2+
FROM ubuntu:20.10 as builder
3+
WORKDIR /app/protoc/
4+
COPY protos/ .
5+
RUN apt update && \
6+
apt install -y wget protobuf-compiler unzip && \
7+
wget https://github.com/googleapis/googleapis/archive/master.zip && \
8+
unzip master.zip -d googleapis
9+
10+
RUN protoc -I./googleapis/googleapis-master -I. \
11+
--include_imports \
12+
--include_source_info \
13+
--descriptor_set_out=books.pb books.proto
1314

1415
# Output stage
1516
FROM envoyproxy/envoy:v1.17-latest
16-
COPY ./envoy.yaml /etc/envoy/envoy.yaml
17-
COPY ./protos/books.pb /etc/envoy/protos/books.pb
18-
RUN chmod go+r /etc/envoy/envoy.yaml && \
19-
chmod go+r /etc/envoy/protos/books.pb
17+
COPY --from=builder /app/protoc/books.pb /etc/protos/books.pb
18+
RUN chmod go+r /etc/protos/books.pb

Dockerfile.service

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ RUN CGO_ENABLED=0 GOOS=linux go build .
77
# output stage
88
FROM alpine:3.7
99
WORKDIR /app
10-
COPY --from=builder /go/src/app/hello /app/
10+
COPY --from=builder /go/src/app/books-service /app/
1111
ENV HOST "0.0.0.0"
1212
ENV PORT 9000
1313
EXPOSE 9000
14-
CMD ["./hello"]
14+
CMD ["./books-service"]

Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
GO := go
22
APP_NAME := books-service
33
PROTOC_DESCRIPTOR := protos/books.pb
4+
GOOGLE_APIS_DIR := ../googleapis
45

56
edit: build run
67

@@ -11,7 +12,7 @@ run:
1112
@${APP_NAME}
1213

1314
protoc:
14-
@protoc -I./googleapis -I. \
15+
@protoc -I./${GOOGLE_APIS_DIR} -I. \
1516
--include_imports \
1617
--include_source_info \
1718
--descriptor_set_out=${PROTOC_DESCRIPTOR} \
@@ -20,4 +21,4 @@ protoc:
2021

2122
clean:
2223
@rm ${APP_NAME}
23-
@rm ${PROTOC_DESCRIPTOR}
24+
@rm ${PROTOC_DESCRIPTOR}

README.md

Lines changed: 85 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,116 @@
1-
# Golang gRPC to REST Envoy example
1+
# gRPC to REST Envoy example
2+
3+
An example of how to use the envoy proxy to transcode REST requests to gRPC calls and expose the gRPC service on a single port.
24

35
## Requirements
46

57
The following are required:
68

79
* Docker
8-
* Golang
10+
* Golang 15 or greater
911
* protoc (Protocal Buffer compiler)
1012

13+
## Set Up
14+
15+
In order to compile the `books.proto` file, you first need to clone the [Google API](https://github.com/googleapis/googleapis) repository from Github. This will include the `annotations.proto` file, which is required to provide the capabilities to transcode between REST and gRPC. Then you need to add the Google repository to your local path:
16+
17+
```bash
18+
git clone https://github.com/googleapis/googleapis
19+
20+
GOOGLE_APIS_DIR = <local-google-api-location>
21+
```
22+
1123
## Compiling the protocal buffers
1224

13-
This will compile the `books.proto` protocol buffer and create the descriptor binary required for the envoy proxy.
25+
In order to compile the `books.proto` file, you need to run the `protoc` compiler. This can be done with the included `Makefile`:
1426

1527
```bash
1628
make protoc
1729
```
1830

19-
## Creating the Docker containers
31+
Alternatively, you can directly run the `protoc` compiler:
32+
33+
```bash
34+
protoc -I./${GOOGLE_APIS_DIR} -I. \
35+
--include_imports \
36+
--include_source_info \
37+
--descriptor_set_out=protos/books.pb \
38+
--go-grpc_out=. \
39+
--go_out=. protos/books.proto
40+
```
41+
42+
## Creating the Docker images
43+
44+
To build the Docker containers, run:
2045

2146
```bash
2247
docker-compose build
2348
```
2449

50+
This will create two images:
51+
52+
* `books-envoy` which is the envoy proxy
53+
* `books` which is the book service
54+
55+
To build a specific image, run:
56+
57+
```bash
58+
docker-compose build <service-name>
59+
```
60+
61+
Where `<service-name>` can be replaced with `envoy` for the envoy image or `books` for the book service.
62+
2563
## Running the Docker containers
2664

65+
To create containers for both `books` and `envoy`, run:
66+
2767
```bash
2868
docker-compose up -d
2969
```
3070

31-
## Validating the envoy config
71+
This will run the API on port `8080` and the envoy admin view on port `9901`.
72+
73+
## Running the Books service locally
74+
75+
In order to run the books service locally, first build the application:
76+
77+
```bash
78+
make build
79+
```
80+
81+
Then run the application. By default it will be on port `9000`:
82+
83+
```bash
84+
make run
85+
```
86+
87+
## Deploying on Kubernetes
88+
89+
The books service with envoy can be deployed with Kubernetes. The following files are provided:
90+
91+
* `books-configmap.yaml` - Defines a config map that contains the envoy config for running the service on Kubernetes.
92+
* `books.yaml` - Defines the deployment and service for running the application. The service uses a `NodePort` and will expose the deployment on port `30001`, which can accept REST and gRPC calls.
93+
94+
To deploy the config map:
95+
96+
```bash
97+
kubectl apply -f books-configmap.yaml
98+
```
99+
100+
Then to deploy the service and deployment:
101+
102+
```bash
103+
kubectl apply -f books.yaml
104+
```
105+
106+
**Note**: By default the number of replicas in the deployment is set to 1. Since the data is stored within memory on the container and not in a database, scaling the deployment above 1 may result in differences in the responses with each request.
107+
108+
## Validating the Envoy config
109+
110+
To validate that your Envoy config is valid, run:
32111

33112
```bash
34113
docker run --rm \
35-
-v $(pwd)/envoy/envoy.yaml:/envoy.yaml envoyproxy/envoy:v1.17-latest \
114+
-v $(pwd)/envoy.yaml:/envoy.yaml envoyproxy/envoy:v1.17-latest \
36115
--mode validate -c envoy.yaml
37116
```

books-configmap.yaml

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
apiVersion: v1
2+
kind: ConfigMap
3+
metadata:
4+
name: books-config-map
5+
data:
6+
envoy-yaml-config: |
7+
admin:
8+
access_log_path: /tmp/admin_access.log
9+
address:
10+
socket_address: { address: 0.0.0.0, port_value: 9901 }
11+
12+
static_resources:
13+
listeners:
14+
- name: listener1
15+
address:
16+
socket_address: { address: 0.0.0.0, port_value: 8080 }
17+
filter_chains:
18+
- filters:
19+
- name: envoy.filters.network.http_connection_manager
20+
typed_config:
21+
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
22+
stat_prefix: grpc_json
23+
codec_type: AUTO
24+
route_config:
25+
name: local_route
26+
virtual_hosts:
27+
- name: local_service
28+
domains: ["*"]
29+
routes:
30+
# NOTE: by default, matching happens based on the gRPC route, and not on the incoming request path.
31+
# Reference: https://www.envoyproxy.io/docs/envoy/latest/configuration/http_filters/grpc_json_transcoder_filter#route-configs-for-transcoded-requests
32+
- match: { prefix: "/" }
33+
route: { cluster: books_service, timeout: 60s}
34+
cors:
35+
allow_origin_string_match:
36+
- prefix: "*"
37+
allow_methods: GET, PUT, DELETE, POST, OPTIONS
38+
allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
39+
max_age: "1728000"
40+
expose_headers: grpc-status,grpc-message
41+
http_filters:
42+
- name: envoy.filters.http.grpc_json_transcoder
43+
typed_config:
44+
"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder
45+
proto_descriptor: "/etc/protos/books.pb"
46+
services: ["books.v1.BookService"]
47+
print_options:
48+
add_whitespace: true
49+
always_print_primitive_fields: true
50+
always_print_enums_as_ints: false
51+
preserve_proto_field_names: false
52+
- name: envoy.filters.http.cors
53+
- name: envoy.filters.http.router
54+
55+
clusters:
56+
- name: books_service
57+
connect_timeout: 1.25s
58+
type: LOGICAL_DNS
59+
lb_policy: ROUND_ROBIN
60+
dns_lookup_family: V4_ONLY
61+
typed_extension_protocol_options:
62+
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
63+
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
64+
explicit_http_config:
65+
http2_protocol_options: {}
66+
load_assignment:
67+
cluster_name: books_service
68+
endpoints:
69+
- lb_endpoints:
70+
- endpoint:
71+
health_check_config:
72+
port_value: 9000
73+
address:
74+
socket_address:
75+
address: localhost
76+
port_value: 9000

books.yaml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: books-deployment
5+
labels:
6+
app: books
7+
stage: dev
8+
version: v1
9+
spec:
10+
replicas: 1
11+
selector:
12+
matchLabels:
13+
app: books
14+
stage: dev
15+
version: v1
16+
template:
17+
metadata:
18+
labels:
19+
app: books
20+
stage: dev
21+
version: v1
22+
spec:
23+
containers:
24+
- name: books
25+
image: books:v1
26+
imagePullPolicy: Never
27+
ports:
28+
- containerPort: 9000
29+
protocol: TCP
30+
- name: envoy
31+
image: books-envoy:v1
32+
volumeMounts:
33+
- name: envoy-config
34+
mountPath: /etc/envoy
35+
imagePullPolicy: Never
36+
ports:
37+
- containerPort: 8080
38+
protocol: TCP
39+
- containerPort: 9901
40+
protocol: TCP
41+
volumes:
42+
- name: envoy-config
43+
configMap:
44+
name: books-config-map
45+
items:
46+
- key: envoy-yaml-config
47+
path: envoy.yaml
48+
---
49+
apiVersion: v1
50+
kind: Service
51+
metadata:
52+
name: books-service
53+
spec:
54+
selector:
55+
app: books
56+
stage: dev
57+
version: v1
58+
type: NodePort
59+
ports:
60+
- protocol: TCP
61+
port: 8080
62+
targetPort: 8080
63+
nodePort: 30001

0 commit comments

Comments
 (0)