Compare commits
7 Commits
dev/migrat
...
main
Author | SHA1 | Date | |
---|---|---|---|
b6ac03b838 | |||
108a55c471 | |||
01a2061d70 | |||
8a560405ec | |||
f0959b135f | |||
02d67c0553 | |||
62c93a0c4c |
11
Dockerfile
11
Dockerfile
@ -1,13 +1,8 @@
|
|||||||
FROM traefik:v2.9.5
|
FROM nginx:alpine
|
||||||
|
|
||||||
LABEL author="Piotr Biernat"
|
LABEL author="Piotr Biernat"
|
||||||
LABEL service="api-gateway"
|
LABEL service="api-gw"
|
||||||
LABEL vendor="Egommerce"
|
LABEL vendor="Egommerce"
|
||||||
LABEL version="1.0"
|
LABEL version="1.0"
|
||||||
|
|
||||||
COPY ./api-gateway/etc /etc/traefik
|
COPY ./data/etc/nginx/ /etc/nginx/
|
||||||
COPY ./api-gateway/plugins /plugins-local
|
|
||||||
|
|
||||||
EXPOSE 443 8080
|
|
||||||
|
|
||||||
# ENTRYPOINT ["/traefik"] # FIXME stack->stack config.yml
|
|
||||||
|
15
api-gateway/.vscode/launch.json
vendored
15
api-gateway/.vscode/launch.json
vendored
@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
// 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
4
api-gateway/.vscode/settings.json
vendored
@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"java.configuration.updateBuildConfiguration": "interactive",
|
|
||||||
"maven.view": "hierarchical"
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
################################################################
|
|
||||||
# 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"
|
|
@ -1,6 +0,0 @@
|
|||||||
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: {}
|
|
@ -1,3 +0,0 @@
|
|||||||
# plugin-requestid
|
|
||||||
|
|
||||||
Add X-Request-ID header
|
|
@ -1,3 +0,0 @@
|
|||||||
module git.pbiernat.dev/traefik/plugin-requestid
|
|
||||||
|
|
||||||
go 1.18
|
|
@ -1,61 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
// 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:])
|
|
||||||
}
|
|
43
data/etc/nginx/apigw.conf
Normal file
43
data/etc/nginx/apigw.conf
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
9
data/etc/nginx/apigw_backends.conf
Normal file
9
data/etc/nginx/apigw_backends.conf
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
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
|
||||||
|
}
|
14
data/etc/nginx/apigw_conf.d/basket_api.conf
Normal file
14
data/etc/nginx/apigw_conf.d/basket_api.conf
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# 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/;
|
||||||
|
}
|
32
data/etc/nginx/apigw_conf.d/identity_api.conf
Normal file
32
data/etc/nginx/apigw_conf.d/identity_api.conf
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# 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;
|
||||||
|
# }
|
11
data/etc/nginx/apigw_json_errors.conf
Normal file
11
data/etc/nginx/apigw_json_errors.conf
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
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'; }
|
9
data/etc/nginx/apigw_keys.conf
Normal file
9
data/etc/nginx/apigw_keys.conf
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
map $http_apikey $apigw_client_name {
|
||||||
|
default "";
|
||||||
|
|
||||||
|
"R7HVf14WE5m4d5L3uv2sZU8Y" "identity_api";
|
||||||
|
"fd7uAN3/GKIfvFrOdfEAoo1y" "basket_api";
|
||||||
|
}
|
||||||
|
|
||||||
|
# $ openssl rand -base64 18
|
||||||
|
# 7B5zIqmRGXmrJTFmKa99vcit
|
32
data/etc/nginx/nginx.conf
Normal file
32
data/etc/nginx/nginx.conf
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
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;
|
||||||
|
}
|
@ -1,14 +1,14 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# RUN IN REPO ROOT DIR !!
|
# RUN IN REPO ROOT DIR !!
|
||||||
|
|
||||||
export IMAGE_NAME="git.pbiernat.dev/egommerce/api-gateway"
|
export IMAGE_NAME="git.pbiernat.dev/egommerce/apigw-svc"
|
||||||
|
|
||||||
TARGET=${1:-latest}
|
TARGET=${1:-latest}
|
||||||
|
|
||||||
echo "Building: $IMAGE_NAME:$TARGET"
|
echo "Building: $IMAGE_NAME:$TARGET"
|
||||||
if [ $TARGET = "dev" ]
|
if [ $TARGET = "dev" ]
|
||||||
then
|
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
|
else
|
||||||
docker build --rm --cache-from "$IMAGE_NAME:$TARGET" -t "$IMAGE_NAME:$TARGET" . >/dev/null 2>&1
|
docker build --rm --cache-from "$IMAGE_NAME:$TARGET" -t "$IMAGE_NAME:$TARGET" . >/dev/null 2>&1
|
||||||
fi
|
fi
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# RUN IN REPO ROOT DIR !!
|
# RUN IN REPO ROOT DIR !!
|
||||||
|
|
||||||
export IMAGE_NAME="git.pbiernat.dev/egommerce/api-gateway"
|
export IMAGE_NAME="git.pbiernat.dev/egommerce/apigw-svc"
|
||||||
|
|
||||||
echo $DOCKER_PASSWORD | docker login git.pbiernat.dev -u $DOCKER_USERNAME --password-stdin
|
echo $DOCKER_PASSWORD | docker login git.pbiernat.dev -u $DOCKER_USERNAME --password-stdin
|
||||||
docker push "$IMAGE_NAME:latest"
|
docker push "$IMAGE_NAME:latest"
|
||||||
|
Loading…
Reference in New Issue
Block a user