Skip to content

Commit

Permalink
Merge pull request #26 from BuoyantIO/flynn/split-ingress
Browse files Browse the repository at this point in the history
Have a poor-man's ingress
  • Loading branch information
kflynn authored Oct 2, 2024
2 parents b170446 + b34713b commit 3477886
Show file tree
Hide file tree
Showing 7 changed files with 247 additions and 9 deletions.
3 changes: 3 additions & 0 deletions cmd/generic/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ func main() {
case "color":
server = &faces.NewColorServer("ColorServer").BaseServer

case "ingress":
server = &faces.NewIngressServer("IngressServer").BaseServer

case "load":
fmt.Printf("Running load generator")

Expand Down
8 changes: 8 additions & 0 deletions faces-chart/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@
{{- include "partials.select-errorFraction" (dict "source" .Values.face) -}}
{{- end -}}

{{- define "partials.ingress-image" -}}
{{- include "partials.select-image" (dict "source" .Values.ingress "root" .) -}}
{{- end -}}

{{- define "partials.ingress-imagePullPolicy" -}}
{{- include "partials.select-imagePullPolicy" (dict "source" .Values.ingress "root" .) -}}
{{- end -}}

{{- define "partials.color-image" -}}
{{- include "partials.select-image" (dict "source" .Values.color "default" .Values.backend "root" .) -}}
{{- end -}}
Expand Down
20 changes: 12 additions & 8 deletions faces-chart/templates/face.yaml
Original file line number Diff line number Diff line change
@@ -1,38 +1,42 @@
{{- $name := "face" -}}
{{- if .Values.ingress.enabled -}}
{{- $name = "cell" -}}
{{- end -}}
---
apiVersion: v1
kind: Service
metadata:
name: face
name: {{ $name }}
namespace: {{ .Release.Namespace }}
labels:
service: face
service: {{ $name }}
spec:
type: ClusterIP
selector:
service: face
service: {{ $name }}
ports:
- port: 80
targetPort: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: face
name: {{ $name }}
namespace: {{ .Release.Namespace }}
labels:
service: face
service: {{ $name }}
spec:
replicas: 1
selector:
matchLabels:
service: face
service: {{ $name }}
template:
metadata:
labels:
service: face
service: {{ $name }}
spec:
containers:
- name: face
- name: {{ $name }}
image: {{ include "partials.face-image" . }}
imagePullPolicy: {{ include "partials.face-imagePullPolicy" . }}
ports:
Expand Down
6 changes: 5 additions & 1 deletion faces-chart/templates/faces-gui.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
{{- $serviceType := .Values.gui.serviceType -}}
{{- if .Values.ingress.enabled -}}
{{- $serviceType = "LoadBalancer" -}}
{{- end -}}
---
apiVersion: v1
kind: Service
Expand All @@ -7,7 +11,7 @@ metadata:
labels:
service: faces-gui
spec:
type: {{ .Values.gui.serviceType }}
type: {{ $serviceType }}
selector:
service: faces-gui
ports:
Expand Down
56 changes: 56 additions & 0 deletions faces-chart/templates/ingress.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{{- if .Values.ingress.enabled -}}
---
apiVersion: v1
kind: Service
metadata:
name: face
namespace: {{ .Release.Namespace }}
labels:
service: face
spec:
type: ClusterIP
selector:
service: face
ports:
- port: 80
targetPort: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: face
namespace: {{ .Release.Namespace }}
labels:
service: face
spec:
replicas: 1
selector:
matchLabels:
service: face
template:
metadata:
labels:
service: face
spec:
containers:
- name: face
image: {{ include "partials.ingress-image" . }}
imagePullPolicy: {{ include "partials.ingress-imagePullPolicy" . }}
ports:
- name: http
containerPort: 8000
env:
- name: FACES_SERVICE
value: "ingress"
- name: USER_HEADER_NAME
value: {{ .Values.authHeader | quote }}
- name: CELL_SERVICE
value: {{ .Values.ingress.cellService | quote }}
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 250m
memory: 128Mi
{{- end -}}
8 changes: 8 additions & 0 deletions faces-chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ face:
errorFraction: "20"
delayBuckets: ""

ingress:
enabled: False # If set to True, enables the ingress workload
image: "" # If set, overrides the imageName/imageTag pair
imageName: ghcr.io/buoyantio/faces-workload
imageTag: "" # If not set, uses the defaultImageTag
imagePullPolicy: "" # If not set, uses the default imagePullPolicy
cellService: "cell" # Override if desired

backend:
image: "" # If set, overrides the imageName/imageTag pair
imageName: ghcr.io/buoyantio/faces-workload
Expand Down
155 changes: 155 additions & 0 deletions pkg/faces/ingressserver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// 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 faces

import (
"encoding/json"
"fmt"
"io"
"net/http"
"time"

"github.com/BuoyantIO/faces-demo/v2/pkg/utils"
)

type IngressServer struct {
BaseServer
faceService string
}

type IngressResponse struct {
Smiley string `json:"smiley"`
Color string `json:"color"`
Rate string `json:"rate"`
Errors []string `json:"errors"`
Latency int64 `json:"latency"`
}

func NewIngressServer(serverName string) *IngressServer {
srv := &IngressServer{
BaseServer: BaseServer{
Name: serverName,
},
}

srv.SetupFromEnvironment()

srv.RegisterNormal("/center/", srv.ingressGetHandler)
srv.RegisterNormal("/edge/", srv.ingressGetHandler)

return srv
}

func (srv *IngressServer) SetupFromEnvironment() {
srv.BaseServer.SetupFromEnvironment()

srv.faceService = utils.StringFromEnv("CELL_SERVICE", "cell")

fmt.Printf("%s %s: faceService %v\n", time.Now().Format(time.RFC3339), srv.Name, srv.faceService)
}

func (srv *IngressServer) ingressGetHandler(r *http.Request, rstat *BaseRequestStatus) *BaseServerResponse {
start := time.Now()

response := BaseServerResponse{
StatusCode: http.StatusOK,
}

errors := []string{}

smiley, _ := Smileys.Lookup(Defaults["smiley"])
color := Colors.Lookup(Defaults["color"])
rateStr := fmt.Sprintf("%.1f RPS", srv.CurrentRate())

if rstat.IsRateLimited() {
errors = append(errors, rstat.Message())
smiley, _ = Smileys.Lookup(Defaults["smiley-ratelimit"])
color = Colors.Lookup(Defaults["color-ratelimit"])
} else {
url := fmt.Sprintf("http://%s%s", srv.faceService, r.URL.Path)

if srv.debugEnabled {
fmt.Printf("%s %s: %s starting\n", time.Now().Format(time.RFC3339), srv.Name, url)
}

req, err := http.NewRequest("GET", url, nil)

if err != nil {
errors = append(errors, fmt.Sprintf("failed to create request: %v", err))
// No need to change smiley and color here.
} else {
// Copy headers from the original request
req.Header.Add(srv.userHeaderName, r.Header.Get(srv.userHeaderName))
req.Header.Add("User-Agent", r.Header.Get("User-Agent"))

resp, err := http.DefaultClient.Do(req)

if err != nil {
errors = append(errors, fmt.Sprintf("request failed: %v", err))
// No need to change smiley and color here.
} else {
defer resp.Body.Close()

rcode := resp.StatusCode

if srv.debugEnabled {
fmt.Printf("%s %s: %s returned %d\n", time.Now().Format(time.RFC3339), srv.Name, url, rcode)
}

response.StatusCode = rcode

body, err := io.ReadAll(resp.Body)

if err != nil {
errors = append(errors, fmt.Sprintf("failed to read response body: %v", err))
// No need to change smiley and color here.
} else {
var ingressResp IngressResponse
err := json.Unmarshal(body, &ingressResp)

if err != nil {
errors = append(errors, fmt.Sprintf("failed to unmarshal response: %v", err))
// No need to change smiley and color here.
} else {
smiley = ingressResp.Smiley
color = ingressResp.Color
rateStr = ingressResp.Rate
errors = ingressResp.Errors
}
}
}
}
}

end := time.Now()
latency := end.Sub(start)

response.Data = map[string]interface{}{
"smiley": smiley,
"color": color,
"rate": rateStr,
"errors": errors,
"latency": latency.Milliseconds(),
}

if srv.debugEnabled {
fmt.Printf("%s %s: %s, %s (%dms): %v\n", time.Now().Format(time.RFC3339), srv.Name, smiley, color, latency.Milliseconds(), errors)
}

return &response
}

0 comments on commit 3477886

Please sign in to comment.