Compare commits

..

2 Commits

Author SHA1 Message Date
1c68b310b7 Migrated to traefik proxy
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-30 02:22:50 +01:00
943b1cb30e fixes
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-13 03:34:53 +01:00
19 changed files with 237 additions and 156 deletions

View File

@ -1,8 +1,13 @@
FROM nginx:alpine
FROM traefik:v2.9.5
LABEL author="Piotr Biernat"
LABEL service="api-gw"
LABEL service="api-gateway"
LABEL vendor="Egommerce"
LABEL version="1.0"
COPY ./data/etc/nginx/ /etc/nginx/
COPY ./api-gateway/etc /etc/traefik
COPY ./api-gateway/plugins /plugins-local
EXPOSE 443 8080
# ENTRYPOINT ["/traefik"] # FIXME stack->stack config.yml

15
api-gateway/.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Debug App",
"request": "launch",
"mainClass": "com.egommerce.apigateway.Bootstrap",
"projectName": "api-gateway"
}
]
}

4
api-gateway/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"java.configuration.updateBuildConfiguration": "interactive",
"maven.view": "hierarchical"
}

View File

@ -0,0 +1,76 @@
################################################################
# global:
# checkNewVersion: true
# sendAnonymousUsage: true
################################################################
entryPoints:
https:
address: :443
transport:
respondingTimeouts:
readTimeout: '10ms'
writeTimeout: '10ms'
idleTimeout: '20ms'
db:
address: :5432
mongodb:
address: :27017
eventbus:
address: :5672
# redis:
# address: :6379
################################################################
serversTransport:
# # insecureSkipVerify: true
rootCAs:
- /etc/traefik/certs/identity-svc/server.cert
- /etc/traefik/certs/basket-svc/server.cert
- /etc/traefik/certs/catalog-svc/server.cert
- /etc/traefik/certs/postgres-db/server.cert
# - /etc/traefik/certs/api-eventbus/server.cert
################################################################
api:
insecure: true
# dashboard: true
################################################################
providers:
# file:
# directory: /etc/traefik/services
################################################################
docker:
# Docker server endpoint. Can be a tcp or a unix socket endpoint.
# endpoint: unix:///var/run/docker.sock
exposedByDefault: false
# network: api-gateway-network
# useBindPortIP: true
# Default host rule.
# Optional
# Default: "Host(`{{ normalize .Name }}`)"
# defaultRule: Host(`{{ normalize .Name }}.docker.localhost`)
################################################################
consulCatalog:
exposedByDefault: false
# serviceName: api-gateway
refreshInterval: 30s
endpoint:
address: api-registry:8500
################################################################
log:
level: DEBUG
# filePath: log/traefik.log
# format: json
################################################################
# accessLog: {}
################################################################
experimental:
localPlugins:
requestid:
moduleName: "git.pbiernat.dev/traefik/plugin-requestid"

View File

@ -0,0 +1,6 @@
displayName: Add X-Request-ID Header
type: middleware
import: git.pbiernat.dev/traefik/plugin-requestid
summary: 'Add a X-Request-ID header for tracing'
testData: {}

View File

@ -0,0 +1,3 @@
# plugin-requestid
Add X-Request-ID header

View File

@ -0,0 +1,3 @@
module git.pbiernat.dev/traefik/plugin-requestid
go 1.18

View File

@ -0,0 +1,61 @@
package plugin_requestid
import (
"context"
"fmt"
"net/http"
)
const defaultHeaderName = "X-Request-ID"
// Config plugin configuration
type Config struct {
HeaderName string `json:"headerName"`
}
// CreateConfig create default plugin configuration
func CreateConfig() *Config {
return &Config{
HeaderName: defaultHeaderName,
}
}
// RequestIDHeader
type RequestIDHeader struct {
headerName string
name string
next http.Handler
}
// New create new RequestIDHeader
func New(ctx context.Context, next http.Handler, config *Config, name string) (http.Handler, error) {
hdr := &RequestIDHeader{
next: next,
name: name,
}
if config == nil {
return nil, fmt.Errorf("config can not be nil")
}
if config.HeaderName == "" {
hdr.headerName = defaultHeaderName
} else {
hdr.headerName = config.HeaderName
}
return hdr, nil
}
func (r *RequestIDHeader) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
uuid := newUUID().String()
// header injection to backend service
req.Header.Add(r.headerName, uuid)
// header injection to client response
rw.Header().Add(r.headerName, uuid)
r.next.ServeHTTP(rw, req)
}

View File

@ -0,0 +1,58 @@
// source: https://github.com/trinnylondon/traefik-add-trace-id/blob/master/rand-utils.go
package plugin_requestid
import (
"crypto/rand"
"encoding/hex"
"io"
)
var rander = rand.Reader // random function
type UUID [16]byte
func must(uuid UUID, err error) UUID {
if err != nil {
panic(err)
}
return uuid
}
func newUUID() UUID {
return must(newRandom())
}
func newRandom() (UUID, error) {
return newRandomFromReader(rander)
}
// newRandomFromReader returns a UUID based on bytes read from a given io.Reader.
func newRandomFromReader(r io.Reader) (UUID, error) {
var uuid UUID
_, err := io.ReadFull(r, uuid[:])
if err != nil {
return UUID{}, err
}
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
return uuid, nil
}
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// , or "" if uuid is invalid.
func (uuid UUID) String() string {
var buf [36]byte
encodeHex(buf[:], uuid)
return string(buf[:])
}
func encodeHex(dst []byte, uuid UUID) {
hex.Encode(dst, uuid[:4])
dst[8] = '-'
hex.Encode(dst[9:13], uuid[4:6])
dst[13] = '-'
hex.Encode(dst[14:18], uuid[6:8])
dst[18] = '-'
hex.Encode(dst[19:23], uuid[8:10])
dst[23] = '-'
hex.Encode(dst[24:], uuid[10:])
}

View File

@ -1,43 +0,0 @@
include apigw_backends.conf;
include apigw_keys.conf;
server {
access_log /var/log/nginx/apigw_access.log main;
error_log /var/log/nginx/apigw_error.log warn;
listen 80;
# listen 443 ssl;
# server_name apigw_svc; # container name from stack config
# server_name api.example.com;
# TLS config
# ssl_certificate /etc/ssl/certs/apigw.example.com.crt;
# ssl_certificate_key /etc/ssl/private/apigw.example.com.key;
# ssl_session_cache shared:SSL:10m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_protocols TLSv1.2 TLSv1.3;
# API definitions, one per file
include apigw_conf.d/*.conf;
# Error responses
# error_page 404 = @400; # Treat invalid paths as bad requests
proxy_intercept_errors on; # Do not send backend errors to client
include apigw_json_errors.conf; # API client-friendly JSON errors
default_type application/json; # If no content-type, assume JSON
# API key validation
location = /_validate_apikey {
internal;
if ($http_apikey = "") {
return 401; # Unauthorized
}
if ($apigw_client_name = "") {
return 403; # Forbidden
}
return 204; # OK (no content)
}
}

View File

@ -1,9 +0,0 @@
upstream identity_api {
# zone inventory_service 64k;
server identity_svc:8080; # container name from stack config
}
upstream basket_api {
# zone pricing_service 64k;
server basket_svc:8080; # container name from stack config
}

View File

@ -1,14 +0,0 @@
# Basket API
#
location /api/basket/ {
access_log /var/log/nginx/basket_access.log main;
error_log /var/log/nginx/basket_error.log warn;
auth_request /_validate_apikey;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header User-Agent "api-gw"; # TMP - FIXME
proxy_pass http://basket_api/;
}

View File

@ -1,32 +0,0 @@
# Identity API
#
location /api/identity/ {
access_log /var/log/nginx/identity_access.log main;
error_log /var/log/nginx/identity_error.log warn;
auth_request /_validate_apikey;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header User-Agent "egommerce-api-gateway/0.1"; # TMP - FIXME
proxy_pass http://identity_api/;
}
# # URI routing
# #
# location = /api/warehouse/inventory { # Complete inventory
# proxy_pass http://warehouse_inventory;
# }
# location ~ ^/api/warehouse/inventory/shelf/[^/]+$ { # Shelf inventory
# proxy_pass http://warehouse_inventory;
# }
# location ~ ^/api/warehouse/inventory/shelf/[^/]+/box/[^/]+$ { # Box on shelf
# proxy_pass http://warehouse_inventory;
# }
# location ~ ^/api/warehouse/pricing/[^/]+$ { # Price for specific item
# proxy_pass http://warehouse_pricing;
# }

View File

@ -1,11 +0,0 @@
error_page 400 = @400;
location @400 { return 400 '{"status":400,"message":"Bad request"}\n'; }
error_page 401 = @401;
location @401 { return 401 '{"status":401,"message":"Unauthorized"}\n'; }
error_page 403 = @403;
location @403 { return 403 '{"status":403,"message":"Forbidden"}\n'; }
error_page 404 = @404;
location @404 { return 404 '{"status":404,"message":"Resource not found"}\n'; }

View File

@ -1,9 +0,0 @@
map $http_apikey $apigw_client_name {
default "";
"R7HVf14WE5m4d5L3uv2sZU8Y" "identity_api";
"fd7uAN3/GKIfvFrOdfEAoo1y" "basket_api";
}
# $ openssl rand -base64 18
# 7B5zIqmRGXmrJTFmKa99vcit

View File

@ -1,32 +0,0 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/apigw.conf;
}

View File

@ -1,14 +1,14 @@
#!/bin/sh
# RUN IN REPO ROOT DIR !!
export IMAGE_NAME="git.pbiernat.dev/egommerce/apigw-svc"
export IMAGE_NAME="git.pbiernat.dev/egommerce/api-gateway"
TARGET=${1:-latest}
echo "Building: $IMAGE_NAME:$TARGET"
if [ $TARGET = "dev" ]
then
docker build --rm --no-cache -t "$IMAGE_NAME:dev" . >/dev/null 2>&1
docker build --rm --no-cache -t "$IMAGE_NAME:dev" . # >/dev/null 2>&1
else
docker build --rm --cache-from "$IMAGE_NAME:$TARGET" -t "$IMAGE_NAME:$TARGET" . >/dev/null 2>&1
fi

View File

@ -1,7 +1,7 @@
#!/bin/sh
# RUN IN REPO ROOT DIR !!
export IMAGE_NAME="git.pbiernat.dev/egommerce/apigw-svc"
export IMAGE_NAME="git.pbiernat.dev/egommerce/api-gateway"
echo $DOCKER_PASSWORD | docker login git.pbiernat.dev -u $DOCKER_USERNAME --password-stdin
docker push "$IMAGE_NAME:latest"

0
test
View File