Skip to content

Commit

Permalink
Merge 1.3 (#13)
Browse files Browse the repository at this point in the history
* Rewrite Dockerfile

* Fix dev Dockerfile

* Update dockerfiles and configuration accessor

* Add more test suites

* Add gatling tests

* Enhance cache speed and tests

* Test coverage over 60%

* Improve cache speed and post results

* Implement by regex configuration

* Refactoring and performance update done

* Update results

* Upgrades

* Introduce Ristretto cache module
* Increase performance by 43 percent
* Close unused channels

* GH action setup on tag creation

* Update docker-compose for prod

* Generate artifacts
* Update README
* Update docker-compose files
* Update configuration.sample

* Add package builder/releaser
  • Loading branch information
darkweak committed Oct 1, 2020
1 parent 7893e39 commit 04496b6
Show file tree
Hide file tree
Showing 29 changed files with 1,087 additions and 225 deletions.
63 changes: 63 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Build container and publish to docker hub

on:
create:
tags: ["v*"]

jobs:
generate-binary:
name: Generate binary
runs-on: ubuntu-latest
steps:
-
name: Get tag name
run: echo ::set-env name=RELEASE_VERSION::${GITHUB_REF#refs/*/}
-
name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
-
name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
-
name: Build & push Docker image containing only binary
id: docker_build
uses: docker/build-push-action@v2
with:
push: true
file: ./Dockerfile-prod
tags: |
darkweak/souin:latest
darkweak/souin:${{ env.RELEASE_VERSION }}
generate-artifacts:
name: Generate cross-platform builds
runs-on: ubuntu-latest
steps:
-
name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.13
-
name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
20 changes: 11 additions & 9 deletions Dockerfile-dev
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
FROM golang:1.13-alpine
FROM golang:1.13-alpine AS souin

RUN apk update && apk upgrade && \
apk add --no-cache bash git openssh gcc libc-dev
ENV GOPATH /app
RUN go get -u \
golang.org/x/lint/golint \
github.com/allegro/bigcache \
github.com/dgraph-io/ristretto \
github.com/fsnotify/fsnotify \
github.com/go-redis/redis \
gopkg.in/yaml.v2

RUN mkdir -p /app/src/github.com/darkweak/souin
RUN mkdir -p /ssl
Expand All @@ -10,16 +18,10 @@ ADD ./cache /app/src/github.com/darkweak/souin/cache
ADD ./errors /app/src/github.com/darkweak/souin/errors
ADD ./providers /app/src/github.com/darkweak/souin/providers
ADD ./default/server.* /app/src/github.com/darkweak/souin/
ADD ./configuration/* /app/src/github.com/darkweak/souin/configuration/
ADD ./configuration/configuration.yml /
ADD ./configuration /app/src/github.com/darkweak/souin/configuration

WORKDIR /app/src/github.com/darkweak/souin
ENV GOPATH /app
RUN go get -u \
golang.org/x/lint/golint \
github.com/allegro/bigcache \
github.com/fsnotify/fsnotify \
github.com/go-redis/redis \
gopkg.in/yaml.v2

EXPOSE 80

Expand Down
40 changes: 26 additions & 14 deletions Dockerfile-prod
Original file line number Diff line number Diff line change
@@ -1,31 +1,43 @@
FROM golang:1.13-alpine
FROM golang:1.13-alpine AS builder

RUN apk update && apk upgrade && \
apk add --no-cache bash git openssh gcc libc-dev
ENV GOPATH /app
ENV GOOS linux
ENV GOARCH arm64
RUN go get -u \
golang.org/x/lint/golint \
github.com/allegro/bigcache \
github.com/dgraph-io/ristretto \
github.com/fsnotify/fsnotify \
github.com/go-redis/redis \
gopkg.in/yaml.v2

RUN mkdir -p /app/src/github.com/darkweak/cmd
RUN mkdir -p /ssl
RUN mkdir -p /app/src/github.com/darkweak/souin
RUN mkdir -p /ssl
ADD ./*.go /app/src/github.com/darkweak/souin/
ADD ./cache /app/src/github.com/darkweak/souin/cache
ADD ./errors /app/src/github.com/darkweak/souin/errors
ADD ./providers /app/src/github.com/darkweak/souin/providers
ADD ./default/server.* /app/src/github.com/darkweak/souin/
ADD ./configuration/configuration.yml /
ADD ./configuration/* /app/src/github.com/darkweak/souin/configuration/
ADD ./entrypoint.sh /app/src/github.com/darkweak/souin/entrypoint.sh

WORKDIR /app/src/github.com/darkweak/souin
ENV GOPATH /app
ENV GOOS linux
ENV GOARCH arm
RUN go get -u \
golang.org/x/lint/golint \
github.com/allegro/bigcache \
github.com/fsnotify/fsnotify \
github.com/go-redis/redis \
gopkg.in/yaml.v2
RUN chmod 755 ./entrypoint.sh

RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a \
-tags netgo -ldflags '-w -extldflags "-static"' -o /app/cmd/souin .

EXPOSE 80

ENTRYPOINT ["./entrypoint.sh"]
FROM alpine:latest AS souin

COPY --from=builder /app/cmd/souin .
COPY --from=builder /app/src/github.com/darkweak/souin/configuration .
COPY --from=builder /ssl/ .
COPY --from=builder /app/src/github.com/darkweak/souin/server.crt .
COPY --from=builder /app/src/github.com/darkweak/souin/server.key .
RUN chmod +x ./souin

CMD ["./souin"]
9 changes: 8 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: build-app build-dev create-network down env-dev env-prod help lint tests up validate
.PHONY: build-app build-dev coverage create-network down env-dev env-prod gatling generate-plantUML help lint log tests up validate

DC=docker-compose
DC_BUILD=$(DC) build
Expand All @@ -12,6 +12,10 @@ build-dev: env-dev ## Build containers with dev env vars
$(DC_BUILD) souin
$(MAKE) up

coverage: ## Show code coverage
$(DC_EXEC) souin go test ./... -coverprofile cover.out
$(DC_EXEC) souin go tool cover -func cover.out

create-network: ## Create network
docker network create your_network

Expand All @@ -26,6 +30,9 @@ env-prod: ## Up container with prod env vars
cp Dockerfile-prod Dockerfile
cp docker-compose.yml.prod docker-compose.yml

gatling: ## Launch gatling scenarios
cd ./gatling && $(DC) up

generate-plantUML: ## Generate plantUML diagrams
cd ./docs/plantUML && sh generate.sh && cd ../..

Expand Down
80 changes: 52 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
5. [Examples](#examples)
5.1. [Træfik container](#træfik-container)
6. [SSL](#ssl)
6.1. [Træfik](#træfik)
6.1. [Træfik](#træfik)
6.2. [Apache](#apache)
6.3. [Nginx](#nginx)
6. [Credits](#credits)

[![Travis CI](https://travis-ci.com/Darkweak/Souin.svg?branch=master)](https://travis-ci.com/Darkweak/Souin)

Expand All @@ -22,49 +25,72 @@ Souin is a new cache system suitable for every reverse-proxy. It will be placed
As it's written in go, it can be deployed on any server and thanks to the docker integration, it will be easy to install on top of a Swarm or a kubernetes instance.

## Configuration
The configuration file is stored at `configuration/configuration.yml`. You can edit it provided you fill at least the required parameters as shown below.
The configuration file is stored at `/anywhere/configuration.yml`. You can edit it provided you fill at least the required parameters as shown below.

### Required configuration
```yaml
ttl: 100 #TTL in second
reverse_proxy_url: 'http://traefik' # The reverse-proxy http address
cache:
port:
default_cache: # Required part
port: # Ports to expose Souin
web: 80
tls: 443
ttl: 10 # Default TTL
reverse_proxy_url: 'http://traefik' # If it's in the same network you can use http://your-service. Then just use https://yourdomain.com
```
This is a fully working minimal configuration for a Souin instance

| Key | Description | Value example |
|:---:|:---:|:---:|
|`ttl`|Duration to cache request (in seconds)|10|
|`reverse_proxy_url`|The reverse-proxy's instance URL (Apache, Nginx, Træfik...)|- `http://yourservice` (Container way)<br/>`http://localhost:81` (Local way)|
|`cache.port.{web,tls}`|The device's local HTTP/TLS port that Souin should be listening on |Respectively `80` and `443`|
|`default_cache.port.{web,tls}`|The device's local HTTP/TLS port that Souin should be listening on |Respectively `80` and `443`|
|`default_cache.ttl`|Duration to cache request (in seconds)|10|
|`reverse_proxy_url`|The reverse-proxy's instance URL (Apache, Nginx, Træfik...)|- `http://yourservice` (Container way)<br/>`http://localhost:81` (Local way)<br/>`http://yourdomain.com:81` (Network way)|

### Optional configuration
```yaml
redis:
url: 'redis:6379' # Redis http address, only used for redis provider
regex:
exclude: 'ARegexHere'
ssl_providers: # Must match your volumes to /ssl/{provider}.json
# /anywhere/configuration.yml
default_cache:
headers: # Default headers concatenated in stored keys
- Authorization
providers:
- all # Enable all providers by default
redis: # Redis configuration
url: 'redis:6379'
regex:
exclude: 'ARegexHere' # Regex to exclude from cache
ssl_providers: # The {providers}.json to use
- traefik
cache:
headers:
- Authorization # Can be any other headers
providers: # By default it will use in-memory and redis cache. It can be either `all`, `redis` or `memory`.
- all # Can be set to all if you want to enable all providers instead of specifying each one
# - memory
# - redis
urls:
'https:\/\/domain.com\/first-.+': # First regex route configuration
ttl: 1000 # Override default TTL
providers: # Providers list (each item must be in default providers list)
- redis
- memory
- ristretto
'https:\/\/domain.com\/second-route': # Second regex route configuration
ttl: 10 # Override default TTL
headers: # Override default headers
- Authorization
providers: # Providers list (each item must be in default providers list)
- memory
'https?:\/\/mysubdomain\.domain\.com': # Third regex route configuration
ttl: 50
headers: # Override default headers
- Authorization
- 'Content-Type'
providers: # Providers list (each item must be in default providers list)
- redis
```

| Key | Description | Value example |
|:---:|:---:|:---:|
|`redis.url`|The redis url, used if you enabled it in the provider section|`redis:6379` (container way) and `http://yourdomain.com:6379` (network way)|
|`regex.exclude`|The regex used to prevent paths being cached|`^[A-z]+.*$`|
|`default_cache.headers`|List of headers to include to the cache|`- Authorization`<br/><br/>`- Content-Type`<br/><br/>`- X-Additional-Header`|
|`default_cache.providers`|Your providers list to cache your data, by default it will use all systems|`- all`<br/><br/>`- memory`<br/><br/>`- redis`|
|`default_cache.redis.url`|The redis url, used if you enabled it in the provider section|`redis:6379` (container way) and `http://yourdomain.com:6379` (network way)|
|`default_cache.regex.exclude`|The regex used to prevent paths being cached|`^[A-z]+.*$`|
|`ssl_providers`|List of your providers handling certificates|`- traefik`<br/><br/>`- nginx`<br/><br/>`- apache`|
|`cache.headers`|List of headers to include to the cache|`- Authorization`<br/><br/>`- Content-Type`<br/><br/>`- X-Additional-Header`|
|`cache.providers`|Your providers list to cache your data, by default it will use all systems|`- all`<br/><br/>`- memory`<br/><br/>`- redis`|
|`urls.{your url or regex}`|List of your custom configuration depending each URL or regex|'https:\/\/yourdomain.com'|
|`urls.{your url or regex}.ttl`|Override the default TTL if defined|99999|
|`urls.{your url or regex}.headers`|Override the default headers if defined|`- Authorization`<br/><br/>`- 'Content-Type'`|
|`urls.{your url or regex}.providers`|Override the default providers if defined|`- redis`<br/><br/>`- ristretto`|

## Diagrams

Expand Down Expand Up @@ -123,8 +149,7 @@ x-networks: &networks

services:
souin:
build:
context: .
image: darkweak/souin:latest
ports:
- 80:80
- 443:443
Expand All @@ -133,7 +158,6 @@ services:
environment:
GOPATH: /app
volumes:
- ./cmd:/app/cmd
- /anywhere/traefik.json:/ssl/traefik.json
<<: *networks

Expand Down
33 changes: 19 additions & 14 deletions cache/providers/abstract.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import (
// AbstractProviderInterface should be implemented in any providers
type AbstractProviderInterface interface {
GetRequestInCache(key string) types.ReverseResponse
SetRequestInCache(key string, value []byte)
SetRequestInCache(key string, value []byte, url configuration.URL)
DeleteRequestInCache(key string)
Init()
Init() error
}

// PathnameNotInRegex check if pathname is in parameter regex var
func PathnameNotInRegex(pathname string, configuration configuration.Configuration) bool {
b, _ := regexp.Match(configuration.Regex.Exclude, []byte(pathname))
// PathnameNotInExcludeRegex check if pathname is in parameter regex var
func PathnameNotInExcludeRegex(pathname string, configuration configuration.Configuration) bool {
b, _ := regexp.Match(configuration.DefaultCache.Regex.Exclude, []byte(pathname))
return !b
}

Expand All @@ -31,19 +31,24 @@ func contains(s []string, e string) bool {
}

// InitializeProviders allow to generate the providers array according to the configuration
func InitializeProviders(configuration configuration.Configuration) *[]AbstractProviderInterface {
var providers []AbstractProviderInterface
func InitializeProviders(configuration configuration.Configuration) map[string]AbstractProviderInterface {
providers := make(map[string]AbstractProviderInterface)

if len(configuration.Cache.Providers) == 0 || contains(configuration.Cache.Providers, "all") {
providers = append(providers, MemoryConnectionFactory(configuration), RedisConnectionFactory(configuration))
if len(configuration.DefaultCache.Providers) == 0 || contains(configuration.DefaultCache.Providers, "all") {
providers["memory"] = MemoryConnectionFactory(configuration)
providers["redis"] = RedisConnectionFactory(configuration)
providers["ristretto"] = RistrettoConnectionFactory(configuration)
} else {
if contains(configuration.Cache.Providers, "redis") {
providers = append(providers, RedisConnectionFactory(configuration))
if contains(configuration.DefaultCache.Providers, "redis") {
providers["redis"] = RedisConnectionFactory(configuration)
}
if contains(configuration.Cache.Providers, "memory") {
providers = append(providers, MemoryConnectionFactory(configuration))
if contains(configuration.DefaultCache.Providers, "memory") {
providers["memory"] = MemoryConnectionFactory(configuration)
}
if contains(configuration.DefaultCache.Providers, "ristretto") {
providers["ristretto"] = RistrettoConnectionFactory(configuration)
}
}

return &providers
return providers
}
Loading

0 comments on commit 04496b6

Please sign in to comment.