Skip to content

Commit

Permalink
Merge pull request #27 from BuoyantIO/flynn/grpc
Browse files Browse the repository at this point in the history
Switch the color workload to gRPC
  • Loading branch information
kflynn authored Oct 6, 2024
2 parents 3477886 + 8442861 commit cadc390
Show file tree
Hide file tree
Showing 17 changed files with 1,086 additions and 27 deletions.
72 changes: 59 additions & 13 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj

version: 1
version: 2

# Allow overriding the registry and image name with environment variables.
env:
Expand All @@ -35,9 +35,9 @@ before:
- make VERSION={{ .Version }} chart

builds:
# "generic" is our build for any random hardware out there.
- id: generic
main: ./cmd/generic
# "generic-" builds are for any random hardware out there.
- id: generic-workload
main: ./cmd/generic/workload
binary: workload
env:
- CGO_ENABLED=0
Expand All @@ -47,6 +47,17 @@ builds:
- arm64
- amd64

- id: generic-color
main: ./cmd/generic/color
binary: color-workload
env:
- CGO_ENABLED=0
goos:
- linux
goarch:
- arm64
- amd64

# "pi" is our build specifically for the Raspberry Pi (it uses Pi GPIO for
# some LEDs and a knob).
- id: pi
Expand All @@ -62,12 +73,13 @@ builds:
# We build GUI and workload images for both arm64 and amd64, then build a
# multiarch manifest from them.
dockers:
### GUI images
- use: buildx
goos: linux
goarch: arm64
dockerfile: Dockerfiles/Dockerfile.gui
ids:
- generic
- generic-workload
image_templates:
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-gui:{{ .Version }}-arm64"
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-gui:latest-arm64"
Expand All @@ -80,7 +92,7 @@ dockers:
goarch: amd64
dockerfile: Dockerfiles/Dockerfile.gui
ids:
- generic
- generic-workload
image_templates:
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-gui:{{ .Version }}-amd64"
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-gui:latest-amd64"
Expand All @@ -89,77 +101,110 @@ dockers:
extra_files:
- assets/html

### Generic workload images: this is the multifunction image that can be any HTTP workload.
- use: buildx
goos: linux
goarch: arm64
dockerfile: Dockerfiles/Dockerfile.workload
ids:
- generic
- generic-workload
image_templates:
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-workload:{{ .Version }}-arm64"
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-workload:latest-arm64"
build_flag_templates:
- "--platform=linux/arm64"
- "--build-arg=WORKLOAD=workload"
- use: buildx
goos: linux
goarch: amd64
dockerfile: Dockerfiles/Dockerfile.workload
ids:
- generic
- generic-workload
image_templates:
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-workload:{{ .Version }}-amd64"
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-workload:latest-amd64"
build_flag_templates:
- "--platform=linux/amd64"
- "--build-arg=WORKLOAD=workload"

### Color workload images: this can only be a gRPC color workload.
- use: buildx
goos: linux
goarch: arm64
dockerfile: Dockerfiles/Dockerfile.workload
ids:
- generic-color
image_templates:
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-color:{{ .Version }}-arm64"
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-color:latest-arm64"
build_flag_templates:
- "--platform=linux/arm64"
- "--build-arg=WORKLOAD=color-workload"
- use: buildx
goos: linux
goarch: amd64
dockerfile: Dockerfiles/Dockerfile.workload
ids:
- generic-color
image_templates:
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-color:{{ .Version }}-amd64"
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-color:latest-amd64"
build_flag_templates:
- "--platform=linux/amd64"
- "--build-arg=WORKLOAD=color-workload"

- use: buildx
goos: linux
goarch: arm64
dockerfile: Dockerfiles/Dockerfile.external-workload
ids:
- generic
- generic-workload
image_templates:
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-external-workload:{{ .Version }}-arm64"
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-external-workload:latest-arm64"
build_flag_templates:
- "--platform=linux/arm64"
- "--build-arg=EXTERNAL_BASE={{ .Env.EXTERNAL_BASE }}"
- "--build-arg=WORKLOAD=workload"
- use: buildx
goos: linux
goarch: amd64
dockerfile: Dockerfiles/Dockerfile.external-workload
ids:
- generic
- generic-workload
image_templates:
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-external-workload:{{ .Version }}-amd64"
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-external-workload:latest-amd64"
build_flag_templates:
- "--platform=linux/amd64"
- "--build-arg=EXTERNAL_BASE={{ .Env.EXTERNAL_BASE }}"
- "--build-arg=WORKLOAD=workload"
- use: buildx
goos: linux
goarch: arm64
dockerfile: Dockerfiles/Dockerfile.bel-external-workload
ids:
- generic
- generic-workload
image_templates:
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-bel-external-workload:{{ .Version }}-arm64"
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-bel-external-workload:latest-arm64"
build_flag_templates:
- "--platform=linux/arm64"
- "--build-arg=EXTERNAL_BASE={{ .Env.BEL_EXTERNAL_BASE }}"
- "--build-arg=WORKLOAD=workload"
- use: buildx
goos: linux
goarch: amd64
dockerfile: Dockerfiles/Dockerfile.bel-external-workload
ids:
- generic
- generic-workload
image_templates:
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-bel-external-workload:{{ .Version }}-amd64"
- "{{ .Env.REGISTRY }}/{{ .Env.IMAGE_NAME }}-bel-external-workload:latest-amd64"
build_flag_templates:
- "--platform=linux/amd64"
- "--build-arg=EXTERNAL_BASE={{ .Env.BEL_EXTERNAL_BASE }}"
- "--build-arg=WORKLOAD=workload"

# For the Pi, we only build an external-workload image for arm64. The Pi itself
# is arm64, so there's no point in building for amd64, and we're not going to try
Expand Down Expand Up @@ -276,7 +321,8 @@ archives:
- id: generic
name_template: '{{ .ProjectName }}_generic_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
builds:
- generic
- generic-workload
- generic-color
- id: pi
name_template: '{{ .ProjectName }}_pi_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
builds:
Expand Down
3 changes: 2 additions & 1 deletion Dockerfiles/Dockerfile.workload
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@

# Use a minimal base image for the final image
FROM scratch AS final
ARG WORKLOAD

# This is associated with the faces-demo repo.
LABEL org.opencontainers.image.source=https://github.com/BuoyantIO/faces-demo

# Copy the compiled binary from the builder stage into the final image
COPY workload /workload
COPY ${WORKLOAD} /workload

# Set the entrypoint to the compiled binary
ENTRYPOINT ["/workload"]
12 changes: 10 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,21 @@ help:
@echo "to the given HELM_REGISTRY. You must set both HELM_REGISTRY and VERSION"
@echo "in order to use this target."
@echo ""
@echo "'make deploy' will build and apply the k8s YAML into the faces"
@echo "namespace. This should be safe to do repeatedly."
@echo "'make proto" will regenerate Go code from protobuf definitions for"
@echo "the color workload. Requires protoc-gen-go to be installed."
@echo ""
@echo "You can also 'make clean' to remove all the Docker-image stuff,"
@echo "or 'make clobber' to smite everything and completely start over."
.PHONY: help

proto: pkg/faces/color_grpc.pb.go pkg/faces/color.pb.go

pkg/faces/color_grpc.pb.go pkg/faces/color.pb.go: pkg/faces/color.proto
protoc \
--go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
pkg/faces/color.proto

images:
goreleaser release --snapshot --clean

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ The Faces architecture is fairly simple:
then composes the responses together and returns the smiley/color
combination to the GUI for display.

`face` uses HTTP to talk to `smiley` and gRPC to talk to `color`.

- The `smiley` workload returns a smiley face. By default, this is a grinning
smiley, U+1F603, but you can set the `SMILEY` environment variable to any
key in the `Smileys` map from `constants.go` to get a different smiley.
Expand Down
121 changes: 121 additions & 0 deletions cmd/generic/color/color.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// SPDX-FileCopyrightText: 2024 Buoyant Inc.
// SPDX-License-Identifier: Apache-2.0
//
// Copyright 2022-2024 Buoyant Inc.
//
// 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 main

import (
"context"
"log/slog"
"net"
"net/http"
"os"

"flag"
"fmt"

"github.com/BuoyantIO/faces-demo/v2/pkg/faces"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

var (
version = "dev"
commit = "none"
date = "unknown"
)

type colorServer struct {
faces.UnimplementedColorServiceServer
provider *faces.ColorProvider
}

func (srv *colorServer) Center(ctx context.Context, req *faces.ColorRequest) (*faces.ColorResponse, error) {
baseResp := srv.provider.Get(int(req.Row), int(req.Column))

slog.Debug(fmt.Sprintf("CENTER: %d, %d => %d, %s\n", req.Row, req.Column, baseResp.StatusCode, baseResp.Body))

switch baseResp.StatusCode {
case http.StatusOK:
color := baseResp.Body

return &faces.ColorResponse{
Color: color,
}, nil

case http.StatusTooManyRequests:
return nil, status.Errorf(codes.ResourceExhausted, "rate limited: %s", baseResp.Body)

default:
return nil, status.Errorf(codes.Internal, "failed to get color: %s", baseResp.Body)
}
}

func (srv *colorServer) Edge(ctx context.Context, req *faces.ColorRequest) (*faces.ColorResponse, error) {
baseResp := srv.provider.Get(int(req.Row), int(req.Column))

slog.Debug(fmt.Sprintf("EDGE: %d, %d => %d, %s\n", req.Row, req.Column, baseResp.StatusCode, baseResp.Body))

switch baseResp.StatusCode {
case http.StatusOK:
color := baseResp.Body

return &faces.ColorResponse{
Color: color,
}, nil

case http.StatusTooManyRequests:
return nil, status.Errorf(codes.ResourceExhausted, "rate limited: %s", baseResp.Body)

default:
return nil, status.Errorf(codes.Internal, "failed to get color: %s", baseResp.Body)
}
}

func main() {
logLevel := &slog.LevelVar{} // INFO

slogOpts := &slog.HandlerOptions{
Level: logLevel,
}

logger := slog.New(slog.NewTextHandler(os.Stdout, slogOpts))
slog.SetDefault(logger)

logLevel.Set(slog.LevelDebug)

// Define a command-line flag for the port number
port := flag.Int("port", 8000, "the port number to listen on")
flag.Parse()

listener, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))

if err != nil {
slog.Error(fmt.Sprintf("failed to listen: %v", err))
os.Exit(1)
}

slog.Info(fmt.Sprintf("listening on %s", listener.Addr()))
var grpcOpts []grpc.ServerOption

cprv := faces.NewColorProviderFromEnvironment()
server := &colorServer{provider: cprv}

grpcServer := grpc.NewServer(grpcOpts...)
faces.RegisterColorServiceServer(grpcServer, server)
grpcServer.Serve(listener)
}
File renamed without changes.
4 changes: 2 additions & 2 deletions faces-chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ smiley2:
color:
color: "" # Override if desired, defaults to colorblind-friendly light blue from the Tol palette
# image: "" # If set, overrides the imageName/imageTag pair
# imageName: "" # If not set, uses backend.imageName
imageName: ghcr.io/buoyantio/faces-color
# imageTag: "" # If not set, uses backend.imageTag
# imagePullPolicy: "" # If not set, uses backend.imagePullPolicy
# errorFraction: "" # If not set, uses backend.errorFraction
Expand All @@ -75,7 +75,7 @@ color2:
enabled: False # If set to True, enables the second color workload
color: "green" # Override if desired, defaults to colorblind-friendly green from the Tol palette
# image: "" # If set, overrides the imageName/imageTag pair
# imageName: "" # If not set, uses backend.imageName
imageName: ghcr.io/buoyantio/faces-color
# imageTag: "" # If not set, uses backend.imageTag
# imagePullPolicy: "" # If not set, uses backend.imagePullPolicy
# errorFraction: "" # If not set, uses backend.errorFraction
Expand Down
Loading

0 comments on commit cadc390

Please sign in to comment.