An HTTP router and reverse proxy for service composition, including use cases like Kubernetes Ingress
Go Other
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
_test_plugins Multi plugins, plugin .conf filles (#598) Apr 18, 2018
_test_plugins_fail Multi plugins, plugin .conf filles (#598) Apr 18, 2018
circuit Properly log the state of the circuits breakers. Nov 18, 2017
cmd provide path modes for Kubernetes ingress paths (#667) Jun 8, 2018
dataclients move the traffic predicate to the decision route (#672) Jun 11, 2018
docs provide path modes for Kubernetes ingress paths (#667) Jun 8, 2018
eskip Using regex delimiter fails in character list in eskip #134 (#578) Mar 15, 2018
eskipfile File watch (#588) Mar 26, 2018
etcd fix etcd auth header test (#617) Apr 14, 2018
filters fix tokeninfo filters to use Set() and not Add() to manipulate querys… Jun 8, 2018
fixtures Implemented TLS support May 18, 2016
img add scaled images Jan 19, 2018
innkeeper all: gofmt -s (#515) Dec 22, 2017
loadbalancer Fix balancer route update (#620) Apr 16, 2018
logging unverifiedAuditLog - fix #631 (#637) May 2, 2018
metrics Feature/add migration path for metrics (#569) Mar 8, 2018
net Source predicate can be by passed in AWS (#533) Jan 17, 2018
oauth close test servers Jun 5, 2016
packaging Expose metrics port 9911 in the Dockerfile Mar 8, 2018
pathmux Add visualization Tree built from pathmux (#445) Oct 6, 2017
predicates Source predicate can be by passed in AWS (#533) Jan 17, 2018
proxy fix #654 - return gw timeout (#665) Jun 6, 2018
ratelimit all: drop underscore if param or receiver is unused (#537) Jan 9, 2018
routing reply also with proxyError after retry of a loadbalanced route to mak… May 28, 2018
script serve's body= parameter accepts a table (#529) Jan 4, 2018
skptesting LUA Scripting (#522) Dec 28, 2017
tracing keep PluginDir, tracing.LoadPlugin as deprecated Mar 23, 2018
.catwatch.yaml added .catwatch.yaml Feb 11, 2016
.gitignore Multi plugins, plugin .conf filles (#598) Apr 18, 2018
.travis.yml use latest go version in travis builds (#461) Oct 18, 2017
.zappr.yaml make Zappr compliant Jun 19, 2017
CONTRIBUTING.md Fix broken markdown links in CONTRIBUTING.md (#447) Oct 10, 2017
LICENSE Move pathmux (#361) Jun 30, 2017
MAINTAINERS remove Raffo from maintainers list (#289) Mar 3, 2017
Makefile run the plugin compilation for the coverprofile and benchmark tasks (#… Apr 18, 2018
SECURITY.md Create SECURITY.md (#347) Jun 20, 2017
delivery.yaml fix build (#601) Mar 27, 2018
doc.go raw migration of the skoap code to skipper (#367) Apr 27, 2018
glide.lock serve's body= parameter accepts a table (#529) Jan 4, 2018
glide.yaml serve's body= parameter accepts a table (#529) Jan 4, 2018
mkdocs.yml document teardown strategy for applications (#666) Jun 6, 2018
plugins.go Multi plugins, plugin .conf filles (#598) Apr 18, 2018
readme.md Update readme.md (#646) May 14, 2018
skipper.go provide path modes for Kubernetes ingress paths (#667) Jun 8, 2018
skipper_test.go Multi plugins, plugin .conf filles (#598) Apr 18, 2018

readme.md

Build Status GoDoc License Go Report Card codecov

Skipper

Skipper

Skipper is an HTTP router and reverse proxy for service composition. It's designed to handle >100k HTTP route definitions with detailed lookup conditions, and flexible augmentation of the request flow with filters. It can be used out of the box or extended with custom lookup, filter logic and configuration sources.

NOTE for Skoap users

The Skoap filters can be found currently in the branch called 'skoap-migration'. The original incubator repository at zalando-incubator/skoap has been removed.

Main features:

An overview of deployments and data-clients shows some use cases to run skipper.

Skipper

  • identifies routes based on the requests' properties, such as path, method, host and headers
  • allows modification of the requests and responses with filters that are independently configured for each route
  • simultaneously streams incoming requests and backend responses
  • optionally acts as a final endpoint (shunt), e.g. as a static file server or a mock backend for diagnostics
  • updates routing rules without downtime, while supporting multiple types of data sources — including etcd, Kubernetes Ingress, Innkeeper (deprecated), static files, route string and custom configuration sources
  • can serve as a Kubernetes Ingress controller without reloads. You can use it in combination with a controller that will route public traffic to your skipper fleet; see AWS example
  • shipped with eskip: a descriptive configuration language designed for routing rules

Skipper provides a default executable command with a few built-in filters. However, its primary use case is to be extended with custom filters, predicates or data sources. Go here for additional documentation.

A few examples for extending Skipper:

Getting Started

Prerequisites/Requirements

In order to build and run Skipper, only the latest version of Go needs to be installed. Skipper can use Innkeeper or Etcd as data sources for routes, or for the simplest cases, a local configuration file. See more details in the documentation: https://godoc.org/github.com/zalando/skipper.

Installation

Skipper is 'go get' compatible. If needed, create a Go workspace first:

mkdir ws
cd ws
export GOPATH=$(pwd)
export PATH=$PATH:$GOPATH/bin

Get the Skipper packages:

go get github.com/zalando/skipper/...

Running

Create a file with a route:

echo 'hello: Path("/hello") -> "https://www.example.org"' > example.eskip

Optionally, verify the file's syntax:

eskip check example.eskip

Start Skipper and make an HTTP request:

skipper -routes-file example.eskip &
curl localhost:9090/hello
Docker

To run the latest Docker container:

docker run registry.opensource.zalan.do/pathfinder/skipper:latest

Authentication Proxy

Skipper can be used as an authentication proxy, to check incoming requests with Basic auth or an OAuth2 provider including audit logging. See the documentation at: https://godoc.org/github.com/zalando/skipper/filters/auth.

Working with the code

Getting the code with the test dependencies (-t switch):

go get -t github.com/zalando/skipper/...

Build and test all packages:

cd src/github.com/zalando/skipper
make deps
make install
make shortcheck

Kubernetes Ingress

Skipper can be used to run as an Kubernetes Ingress controller. Details with examples of Skipper's capabilities and an overview you will can be found in our ingress-controller deployment docs.

For AWS integration, we provide an ingress controller https://github.com/zalando-incubator/kube-ingress-aws-controller, that manage ALBs in front of your skipper deployment. A production example, https://github.com/zalando-incubator/kubernetes-on-aws/blob/dev/cluster/manifests/skipper/daemonset.yaml, can be found in our Kubernetes configuration https://github.com/zalando-incubator/kubernetes-on-aws.

Documentation

Skipper's Documentation and Godoc developer documentation, includes information about deployment use cases and detailed information on these topics:

1 Minute Skipper introduction

The following example shows a skipper routes file in eskip format, that has 3 named routes: baidu, google and yandex.

% cat doc-1min-intro.eskip
baidu:
        Path("/baidu")
        -> setRequestHeader("Host", "www.baidu.com")
        -> setPath("/s")
        -> setQuery("wd", "godoc skipper")
        -> "http://www.baidu.com";
google:
        *
        -> setPath("/search")
        -> setQuery("q", "godoc skipper")
        -> "https://www.google.com";
yandex:
        * && Cookie("yandex", "true")
        -> setPath("/search/")
        -> setQuery("text", "godoc skipper")
        -> tee("http://127.0.0.1:12345/")
        -> "https://yandex.ru";

Matching the route:

  • baidu is using Path() matching to differentiate the HTTP requests to select the route.
  • google is the default matching with wildcard '*'
  • yandex is the default matching with wildcard '*' if you have a cookie "yandex=true"

Request Filters:

  • If baidu is selected, skipper sets the Host header, changes the path and sets a query string to the http request to the backend "http://www.baidu.com".
  • If google is selected, skipper changes the path and sets a query string to the http request to the backend "https://www.google.com".
  • If yandex is selected, skipper changes the path and sets a query string to the http request to the backend "https://yandex.ru". The modified request will be copied to "http://127.0.0.1:12345/"

Run skipper with the routes file doc-1min-intro.eskip shown above

% skipper -routes-file doc-1min-intro.eskip

To test each route you can use curl:

% curl -v localhost:9090/baidu
% curl -v localhost:9090/
% curl -v --cookie "yandex=true" localhost:9090/

To see the request that is made by the tee() filter you can use nc:

[terminal1]% nc -l 12345
[terminal2]% curl -v --cookie "yandex=true" localhost:9090/

3 Minutes Skipper in Kubernetes introduction

Please check out our Kubernetes ingress controller docs.

You should have a base understanding of Kubernetes and Ingress.

Prerequisites: First you have to install skipper-ingress as for example daemonset, create a deployment and a service.

We start to deploy skipper-ingress as a daemonset, use hostNetwork and expose the TCP port 9999 on each Kubernetes worker node for incoming ingress traffic.

% cat skipper-ingress-ds.yaml
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: skipper-ingress
  namespace: kube-system
  labels:
    application: skipper-ingress
    version: v0.9.115
    component: ingress
spec:
  selector:
    matchLabels:
      application: skipper-ingress
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      name: skipper-ingress
      labels:
        application: skipper-ingress
        version: v0.9.115
        component: ingress
      annotations:
        scheduler.alpha.kubernetes.io/critical-pod: ''
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: master
                operator: DoesNotExist
      tolerations:
      - key: CriticalAddonsOnly
        operator: Exists
      hostNetwork: true
      containers:
      - name: skipper-ingress
        image: registry.opensource.zalan.do/pathfinder/skipper:v0.9.115
        ports:
        - name: ingress-port
          containerPort: 9999
          hostPort: 9999
        args:
          - "skipper"
          - "-kubernetes"
          - "-kubernetes-in-cluster"
          - "-address=:9999"
          - "-proxy-preserve-host"
          - "-serve-host-metrics"
          - "-enable-ratelimits"
          - "-experimental-upgrade"
          - "-metrics-exp-decay-sample"
        resources:
          limits:
            cpu: 200m
            memory: 200Mi
          requests:
            cpu: 25m
            memory: 25Mi
        readinessProbe:
          httpGet:
            path: /kube-system/healthz
            port: 9999
          initialDelaySeconds: 5
          timeoutSeconds: 5

We now deploy a simple demo application serving html:

% cat demo-deployment.yaml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: skipper-demo
spec:
  replicas: 2
  template:
    metadata:
      labels:
        application: skipper-demo
    spec:
      containers:
      - name: skipper-demo
        image: registry.opensource.zalan.do/pathfinder/skipper:v0.9.117
        args:
          - "skipper"
          - "-inline-routes"
          - "* -> inlineContent(\"<body style='color: white; background-color: green;'><h1>Hello!</h1>\") -> <shunt>"
        ports:
        - containerPort: 9090

We deploy a service type ClusterIP that we will select from ingress:

% cat demo-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: sszuecs-demo
  labels:
    application: skipper-demo
spec:
  type: ClusterIP
  ports:
    - port: 80
      protocol: TCP
      targetPort: 9090
      name: external
  selector:
    application: sszuecs-demo

To deploy both, you have to run:

% kubectl create -f demo-deployment.yaml
% kubectl create -f demo-svc.yaml

Now we have a skipper-ingress running as daemonset exposing the TCP port 9999 on each worker node, a backend application running with 2 replicas that serves some html on TCP port 9090, and we expose a cluster service on TCP port 80. Besides skipper-ingress, deployment and service can not be reached from outside the cluster. Now we expose the application with Ingress to the external network:

% cat demo-ing.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: skipper-demo
spec:
  rules:
  - host: skipper-demo.<mydomain.org>
    http:
      paths:
      - backend:
          serviceName: skipper-demo
          servicePort: 80

To deploy this ingress, you have to run:

% kubectl create -f demo-ing.yaml

Skipper will configure itself for the given ingress, such that you can test doing:

% curl -v -H"Host: skipper-demo.<mydomain.org>" http://<nodeip>:9999/

The next question you may ask is: how to expose this to your customers?

The answer depends on your setup and complexity requirements. In the simplest case you could add one A record in your DNS *.<mydomain.org> to your frontend loadbalancer IP that directs all traffic from *.<mydomain.org> to all Kubernetes worker nodes on TCP port 9999.

A more complex setup we use in production and can be done with something that configures your frontend loadbalancer, for example kube-aws-ingress-controller, and your DNS, external-dns automatically.

Packaging support

See https://github.com/zalando/skipper/blob/master/packaging/readme.md

In case you want to implement and link your own modules into your skipper for more advanced features like opentracing API support there is https://github.com/skipper-plugins organization to enable you to do so. In order to explain you the build process with custom Go modules there is https://github.com/skipper-plugins/skipper-tracing-build, that is used to build skipper's opentracing package.

Community

User or developer questions can be asked in our public Google Group

We also have a slack channel #skipper in gophers.slack.com. Get an invite at gophers official invite page.

Proposals

We do our proposals open in Skipper's Google drive. If you want to make a proposal feel free to create an issue and if it is a bigger change we will invite you to a document, such that we can work together.